posts - 55,comments - 89,trackbacks - 0
oracle 10g默认需要微软的网络适配器配置。新建一个就行了。
方法,打开控制面板,选者添加硬件—选择是,我已经连接了此硬件,下一步选者最后一项添加新的硬件设备,下一步选择 安装我手动从列表选者的硬件(高级),下一步选者网络适配器,下一步选者Microsoft Loopback
Adapter,按向导提示下一步就行了。完成以后打开你的网上邻居看看是不是多了一个网上连接(2),然后设置它的IP地址如。192.168.1.1.随便就行了,这样在安装oracle的时候就可以用这一个假的网络来连接,蒙骗一下 oracle了。一定可以验证过去
posted @ 2012-08-18 13:38 jiafang83 阅读(908) | 评论 (0)编辑 收藏
    摘自:http://article.pchome.net/content-330924.html

       在过去几年里,Hibernate不断发展,几乎成为Java数据库持久性的事实标准。它非常强大、灵活,而且具备了优异的性能。在本文中,我们将了解如何使用Java 5 注释来简化Hibernate代码,并使持久层的编码过程变得更为轻松。

  传统上,Hibernate的配置依赖于外部 XML 文件:数据库映射被定义为一组 XML 映射文件,并且在启动时进行加载。创建这些映射有很多方法,可以从已有数据库模式或Java类模型中自动创建,也可以手工创建。无论如何,您最终将获得大量的 Hibernate 映射文件。此外,还可以使用工具,通过javadoc样式的注释生成映射文件,尽管这样会给您的构建过程增加一个步骤。

  在最近发布的几个Hibernate版本中,出现了一种基于 Java 5 注释的更为巧妙的新方法。借助新的 Hibernate Annotation 库,即可一次性地分配所有旧映射文件——一切都会按照您的想法来定义——注释直接嵌入到您的 Java 类中,并提供一种强大及灵活的方法来声明持久性映射。籍由自动代码完成和语法突出显示功能,最近发布的Java IDE也为其提供了有力的支持。

  Hibernate Annotation还支持新的 EJB 3 持久性规范。这些规范旨在提供一种标准化的 Java 持久性机制。由于 Hibernate 3 还提供了一些扩展,因此您可以十分轻松地遵从这些标准,并使用 EJB 3 编程模型来对 Hibernate 持久层进行编码。

  现在,让我们来动手使用Hibernate Annotation。

安装 Hibernate Annotation

  要使用 Hibernate Annotation,您至少需要具备 Hibernate 3.2和Java 5。可以从 Hibernate 站点 下载 Hibernate 3.2 和 Hibernate Annotation库。除了标准的 Hibernate JAR 和依赖项之外,您还需要 Hibernate Annotations .jar 文件(hibernate-annotations.jar)、Java 持久性 API (lib/ejb3-persistence.jar)。如果您正在使用 Maven,只需要向 POM 文件添加相应的依赖项即可,如下所示:

 ...

org.hibernate
hibernate
3.2.1.ga


org.hibernate
hibernate-annotations
3.2.0.ga


javax.persistence
persistence-api
1.0

...

  下一步就是获取 Hibernate 会话工厂。尽管无需惊天的修改,但这一工作与使用 Hibernate Annotations有所不同。您需要使用 AnnotationConfiguration 类来建立会话工厂:

sessionFactory = new
AnnotationConfiguration().buildSessionFactory();

  尽管通常使用 元素来声明持久性类,您还是需要在 Hibernate 配置文件(通常是 hibernate.cfg.xml)中声明持久性类:







  近期的许多 Java 项目都使用了轻量级的应用框架,例如 Spring。如果您正在使用 Spring 框架,可以使用 AnnotationSessionFactoryBean 类轻松建立一个基于注释的 Hibernate 会话工厂,如下所示:








org.hibernate.dialect.DerbyDialect
create
...




com.onjava.modelplanes.domain.PlaneType
com.onjava.modelplanes.domain.ModelPlane
...



第一个持久性类

  既然已经知道了如何获得注释所支持的 Hibernate 会话,下面让我们来了解一下带注释的持久性类的情况:

  像在其他任何 Hibernate应用程序中一样,带注释的持久性类也是普通 POJO。差不多可以说是。您需要向 Java 持久性 API (javax.persistence.*)添加依赖项,如果您正在使用任何特定于 Hibernate的扩展,那很可能就是 Hibernate Annotation 程序包(org.hibernate.annotations.*),但除此之外,它们只是具备了持久性注释的普通 POJO 。下面是一个简单的例子:

@Entity
public class ModelPlane {
private Long id;
private String name;
@Id
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

  正像我们所提到的,这非常简单。@Entity 注释声明该类为持久类。@Id 注释可以表明哪种属性是该类中的独特标识符。事实上,您既可以保持字段(注释成员变量),也可以保持属性(注释getter方法)的持久性。后文中将使用基于属性的注释。基于注释的持久性的优点之一在于大量使用了默认值(最大的优点就是 “惯例优先原则(convention over configuration)”)。例如,您无需说明每个属性的持久性——任何属性都被假定为持久的,除非您使用 @Transient 注释来说明其他情况。这简化了代码,相对使用老的 XML 映射文件而言也大幅地减少了输入工作量。

生成主键

  Hibernate 能够出色地自动生成主键。Hibernate/EBJ 3 注释也可以为主键的自动生成提供丰富的支持,允许实现各种策略。下面的示例说明了一种常用的方法,其中 Hibernate 将会根据底层数据库来确定一种恰当的键生成策略:

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}

定制表和字段映射

  默认情况下,Hibernate 会将持久类以匹配的名称映射到表和字段中。例如,前一个类可以与映射到以如下代码创建的表中:

CREATE TABLE MODELPLANE
(
ID long,
NAME varchar
)

  如果您是自己生成并维护数据库,那么这种方法很有效,通过省略代码可以大大简化代码维护。然而,这并不能满足所有人的需求。有些应用程序需要访问外部数据库,而另一些可能需要遵从公司的数据库命名惯例。如果有必要,您可以使用 @Table 和 @Column 注释来定制您自己的持久性映射,如下所示:

@Entity
@Table(name="T_MODEL_PLANE")
public class ModelPlane {
private Long id;
private String name;
@Id
@Column(name="PLANE_ID")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name="PLANE_NAME")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

  该内容将映射到下表中:

CREATE TABLE T_MODEL_PLANE
(
PLANE_ID long,
PLANE_NAME varchar
)

  也可以使用其他图和列的属性来定制映射。这使您可以指定诸如列长度、非空约束等详细内容。Hibernate支持大量针对这些注释的属性。下例中就包含了几种属性:

 ...
@Column(name="PLANE_ID", length=80, nullable=true)
public String getName() {
return name;
}
...

映射关系

  Java 持久性映射过程中最重要和最复杂的一环就是确定如何映射表间的关系。像其他产品一样, Hibernate 在该领域中提供了高度的灵活性,但却是以复杂度的增加为代价。我们将通过研究几个常见案例来了解如何使用注释来处理这一问题。

  其中一种最常用的关系就是多对一的关系。假定在以上示例中每个 ModelPlane 通过多对一的关系(也就是说,每个飞机模型只与一种飞机类型建立联系,尽管指定的飞机类型可以与七种飞机模型建立联系)来与 PlaneType 建立联系。可如下进行映射:

 @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
public PlaneType getPlaneType() {
return planeType;
}

  CascadeType 值表明 Hibernate 应如何处理级联操作。

  另一种常用的关系与上述关系相反:一对多再对一关系,也称为集合。在老式的 Hibernate 版本中进行映射或使用注释时,集合令人头疼,这里我们将简要加以探讨,以使您了解如何处理集合,例如,在以上示例中每个 PlaneType 对象都可能会包含一个 ModelPlanes 集合。可映射如下:

 @OneToMany(mappedBy="planeType",
cascade=CascadeType.ALL,
fetch=FetchType.EAGER)
@OrderBy("name")
public List getModelPlanes() {
return modelPlanes;
}

命名查询

  Hibernate 最优秀的功能之一就在于它能够在您的映射文件中声明命名查询。随后即可通过代码中的名称调用此类查询,这使您可以专注于查询,而避免了 SQL 或者 HQL 代码分散于整个应用程序中的情况。

  也可以使用注释来实现命名查询,可以使用 @NamedQueries 和 @NamedQuery 注释,如下所示:

@NamedQueries(
{
@NamedQuery(
name="planeType.findById",
query="select p from PlaneType p left join fetch p.modelPlanes where id=:id"
),
@NamedQuery(
name="planeType.findAll",
query="select p from PlaneType p"
),
@NamedQuery(
name="planeType.delete",
query="delete from PlaneType where id=:id"
)
}
)

  一旦完成了定义,您就可以像调用其他任何其他命名查询一样来调用它们。

结束语

  Hibernate 3 注释提供了强大而精致的 API,简化了 Java 数据库中的持久性代码,本文中只进行了简单的讨论。您可以选择遵从标准并使用 Java 持久性 API,也可以利用特定于 Hibernate的扩展,这些功能以损失可移植性为代价提供了更为强大的功能和更高的灵活性。无论如何,通过消除对 XML 映射文件的需求,Hibernate 注释将简化应用程序的维护,同时也可以使您对EJB 3 有初步认识。来试试吧!

posted @ 2009-07-26 14:00 jiafang83 阅读(328) | 评论 (0)编辑 收藏
摘自:http://www.javaeye.com/topic/95822

school和userMember是一对多关系:

SchoolInfo.java

 1import javax.persistence.CascadeType;   
 2import javax.persistence.Column;   
 3import javax.persistence.Entity;   
 4import javax.persistence.FetchType;   
 5import javax.persistence.GeneratedValue;   
 6import javax.persistence.Id;   
 7import javax.persistence.OneToMany;   
 8import javax.persistence.Table;   
 9import javax.persistence.Temporal;   
10import javax.persistence.TemporalType;   
11   
12import org.hibernate.annotations.Formula;   
13import org.hibernate.annotations.GenericGenerator;   
14   
15@Entity   
16@Table(name = "school_info")   
17public class SchoolInfo implements java.io.Serializable {   
18   
19    @Id   
20    @GeneratedValue(generator = "system-uuid")   
21    @GenericGenerator(name = "system-uuid", strategy = "uuid")   
22    private String id;//hibernate的uuid机制,生成32为字符串   
23   
24    @Column(name = "actcodeId", updatable = false, nullable = true, length = 36)   
25    private String actcodeId;   
26   
27    @Formula("select COUNT(*) from school_info")   
28    private int count;   
29   
30    @Temporal(TemporalType.TIMESTAMP)//不用set,hibernate会自动把当前时间写入   
31    @Column(updatable = false, length = 20)   
32    private Date createTime;   
33   
34    @Temporal(TemporalType.TIMESTAMP)   
35    private Date updateTime;// 刚开始我默认insertable=false,但会读取出错提示如下:   
36    // Value '0000-00-00' can not be represented as java.sql.Timestamp   
37   
38    // mappedBy="school"就相当于inverse=true,(mappedBy指定的是不需要维护关系的一端)   
39    // 应该注意的是mappedBy值对应@ManyToOne标注的属性,我刚开始写成"schoolId",让我郁闷了好一会 
40    @OneToMany(mappedBy = "school", cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = UserMember.class)   
41    // 用范性的话,就不用targetEntity了   
42    private List<usermember> users = </usermember>new ArrayList<usermember>();  </usermember> 
43       
44}
   
45

@GeneratedValue(strategy=GenerationType.AUTO)我们常用的自增长机制,我这里采用的是hibernate的uuid生成机制.
需要注意的是import javax.xx.Entity ,而不是org.hibernate.xx.Entity。

郁闷的是我上面用到@Formula,生成的sql竟然是'select COUNT(*) from school_info as formula0_ from school_info schoolinfo0_,当然不能执行了,寻求正解中~!!!!!!!!!

UserMember.java(前面引入的包已经贴过了,下面就不贴了)
 1 @Entity   
 2 @Table(name = "teacher_info")//实体类和数据库表名不一致时,才用这个   
 3 public class UserMember implements java.io.Serializable {   
 4    
 5     @Id   
 6     @GeneratedValue(generator = "system-uuid")   
 7     @GenericGenerator(name = "system-uuid", strategy = "uuid")   
 8     private String id;   
 9    
10     @Column(updatable = false, nullable = false, length = 20)   
11     private String logonName;   
12        
13     @Temporal(TemporalType.TIMESTAMP)   
14     @Column(updatable = false, length = 20)   
15     private Date createTime;   
16    
17     @Temporal(TemporalType.TIMESTAMP)   
18     private Date updateTime;   
19    
20     @ManyToOne(cascade = { CascadeType.MERGE })   
21     @JoinColumn(name = "schoolId")   
22     private SchoolInfo school;   
23     //注意该类就不用声明schoolId属性了,如果不用@JoinColumn指明关联的字段,hibernate默认会是school_id.   
24    
25 }   

posted @ 2009-07-26 13:40 jiafang83 阅读(3176) | 评论 (1)编辑 收藏
posted @ 2009-07-20 22:31 jiafang83 阅读(255) | 评论 (0)编辑 收藏
转载:http://www.cnblogs.com/Truly/archive/2006/12/31/608896.html

JSON定义

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于阅读和编写,同时也易于机器解析和生成。它基于ECMA262语言规范(1999-12第三版)中JavaScript编程语言的一个子集。 JSON采用与编程语言无关的文本格式,但是也使用了类C语言(包括C, C++, C#, Java, JavaScript, Perl, Python等)的习惯,这些特性使JSON成为理想的数据交换格式。

JSON的结构基于下面两点

  • 1. "名称/值"对的集合 不同语言中,它被理解为对象(object),记录(record),结构(struct),字典(dictionary),哈希表(hash table),键列表(keyed list)等
  • 2. 值的有序列表 多数语言中被理解为数组(array)
JSON使用

JSON以一种特定的字符串形式来表示 JavaScript 对象。如果将具有这样一种形式的字符串赋给任意一个 JavaScript 变量,那么该变量会变成一个对象引用,而这个对象就是字符串所构建出来的,好像有点拗口,我们还是用实例来说明。

 这里假设我们需要创建一个User对象,并具有以下属性

  • 用户ID
  • 用户名
  • 用户Email

    您可以使用以下JSON形式来表示User对象:

    {"UserID":11, "Name":"Truly", "Email":"zhuleipro◎hotmail.com"};

    然后如果把这一字符串赋予一个JavaScript变量,那么就可以直接使用对象的任一属性了。

    完整代码:

    <script>
    var User = {"UserID":11, "Name":"Truly", "Email":"zhuleipro◎hotmail.com"}; alert(User.Name); </script>

    实际使用时可能更复杂一点,比如我们为Name定义更详细的结构,使它具有FirstName和LastName:

    {"UserID":11, "Name":{"FirstName":"Truly","LastName":"Zhu"}, "Email":"zhuleipro◎hotmail.com"}

    完整代码:

    <script>
    var User = {"UserID":11, "Name":{"FirstName":"Truly","LastName":"Zhu"}, "Email":"zhuleipro◎hotmail.com"}; alert(User.Name.FirstName); </script>

    现在我们增加一个新的需求,我们某个页面需要一个用户列表,而不仅仅是一个单一的用户信息,那么这里就需要创建一个用户列表数组。
    下面代码演示了使用JSON形式定义这个用户列表:

    [
    {"UserID":11, "Name":{"FirstName":"Truly","LastName":"Zhu"}, "Email":"zhuleipro◎hotmail.com"},
    {"UserID":12, "Name":{"FirstName":"Jeffrey","LastName":"Richter"}, "Email":"xxx◎xxx.com"},
    {"UserID":13, "Name":{"FirstName":"Scott","LastName":"Gu"}, "Email":"xxx2◎xxx2.com"}
    ]


    完整代码:

    <script>
    var UserList = [
    {"UserID":11, "Name":{"FirstName":"Truly","LastName":"Zhu"}, "Email":"zhuleipro◎hotmail.com"},
    {"UserID":12, "Name":{"FirstName":"Jeffrey","LastName":"Richter"}, "Email":"xxx◎xxx.com"},
    {"UserID":13, "Name":{"FirstName":"Scott","LastName":"Gu"}, "Email":"xxx2◎xxx2.com"}
    ];
    alert(UserList[0].Name.FirstName);
    </script>

    事实上除了使用"."引用属性外,我们还可以使用下面语句:

    alert(UserList[0]["Name"]["FirstName"]); 或者 alert(UserList[0].Name["FirstName"]); 

    现在读者应该对JSON的使用有点认识了,归纳为以下几点:

  • 对象是属性、值对的集合。一个对象的开始于“{”,结束于“}”。每一个属性名和值间用“:”提示,属性间用“,”分隔。
  • 数组是有顺序的值的集合。一个数组开始于"[",结束于"]",值之间用","分隔。
  • 值可以是引号里的字符串、数字、true、false、null,也可以是对象或数组。这些结构都能嵌套。
  • 字符串和数字的定义和C或Java基本一致。

    小节

    本文通过一个实例演示,初步了解了JSON 的强大用途。可以归结如下:

  • JSON 提供了一种优秀的面向对象的方法,以便将元数据缓存到客户机上。
  • JSON 帮助分离了验证数据和逻辑。
  • JSON 帮助为 Web 应用程序提供了 Ajax 的本质。
  • posted @ 2009-06-16 01:03 jiafang83 阅读(321) | 评论 (0)编辑 收藏
     转载:http://blog.csdn.net/sdlcn/

    前提 OS: WIN2000
         tomcat已经配置好(tomcat可以到http://jakarta.apache.org/tomcat 下载)
    开始实战啦
    1.准备jstl
       到http://apache.towardex.com/jakarta/taglibs/standard/下载jakarta-taglibs-standard-current.zip
    解压后成为jakarta-taglibs-standard-1.1.1

    2.准备web开发目录
       比如我的web目录为h:\webapp\myweb\(当然可以把你的web应用放在%tomcat_home%\webapps\),称为工作目录Working folder,在工作目录h:\webapp\myweb\下建立WEB-INF\lib,WEB-INF\classes

    3.拷贝.jar文件
       将jakarta-taglibs-standard-1.1.1\lib\下的两个jar文件:standard.jar和jstl.jar文件拷贝到\WEB-INF\lib\下

    4.拷贝.tld文件
     将jakarta-taglibs-standard-1.1.1\tld\下的8个tld类型文件拷到"Working folder\WEB-INF\"下

    5.在\WEB-INF\下建立web.xml文件:
      <?xml version="1.0" encoding="ISO-8859-1"?>

    <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="
    http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
    http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
        version="2.4">
     
      <taglib>
        <taglib-uri>http://java.sun.com/jstl/fmt</taglib-uri>
        <taglib-location>/WEB-INF/fmt.tld</taglib-location>
    </taglib>

    <taglib>
        <taglib-uri>http://java.sun.com/jstl/fmt-rt</taglib-uri>
        <taglib-location>/WEB-INF/fmt-rt.tld</taglib-location>
    </taglib>

    <taglib>
        <taglib-uri>http://java.sun.com/jstl/core</taglib-uri>
        <taglib-location>/WEB-INF/c.tld</taglib-location>
    </taglib>

    <taglib>
        <taglib-uri>http://java.sun.com/jstl/core-rt</taglib-uri>
        <taglib-location>/WEB-INF/c-rt.tld</taglib-location>
    </taglib>

    <taglib>
        <taglib-uri>http://java.sun.com/jstl/sql</taglib-uri>
        <taglib-location>/WEB-INF/sql.tld</taglib-location>
    </taglib>

    <taglib>
        <taglib-uri>http://java.sun.com/jstl/sql-rt</taglib-uri>
        <taglib-location>/WEB-INF/sql-rt.tld</taglib-location>
    </taglib>

    <taglib>
        <taglib-uri>http://java.sun.com/jstl/x</taglib-uri>
        <taglib-location>/WEB-INF/x.tld</taglib-location>
    </taglib>

    <taglib>
        <taglib-uri>http://java.sun.com/jstl/x-rt</taglib-uri>
        <taglib-location>/WEB-INF/x-rt.tld</taglib-location>
    </taglib>

    </web-app>
    6.建立一个名为test.jsp文件
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <%@ page contentType="text/html;charset=GB2312" %>
    <%@ taglib prefix="c" uri="
    http://java.sun.com/jsp/jstl/core"%>
    <html>
    <head>
    <title>测试你的第一个使用到JSTL 的网页</title>
    </head>
    <body>
    <c:out value="欢迎测试你的第一个使用到JSTL 的网页"/>
    </br>你使用的浏览器是:</br>
    <c:out value="${header['User-Agent']}"/>
    <c:set var="a" value="David O'Davies" />
    <c:out value="David O'Davies" escapeXml="true"/>
    </body>
    </html>

    7.开启tomcat,进行调试,我的输出结果是

    欢迎测试你的第一个使用到JSTL 的网页
    你使用的浏览器是:
    Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) David O'Davies

    posted @ 2009-06-14 18:02 jiafang83 阅读(850) | 评论 (0)编辑 收藏

    转载:http://blog.csdn.net/mtzai/archive/2009/05/24/4212490.aspx

    在大多数情况下,为事件处理函数返回false,可以防止默认的事件行为.例如,默认情况下点击一个<a>元素,页面会跳转到该元素href属性指定的页.
     Return False 就相当于终止符,Return True 就相当于执行符。

    在js中return false的作用一般是用来取消默认动作的。比如你单击一个链接除了触发你的
    onclick时间(如果你指定的话)以外还要触发一个默认事件就是执行页面的跳转。所以如果
    你想取消对象的默认动作就可以return false。return false应用比较多的场合有:
    <form name="form1"  onsubmIT="return youfunction();">...... </form>
    <a href="www.***.com" onclick="...;return false;">dddd </a>    .

    <script>
    function test()
    {
      alert("test");
      return false();
    }
    </script>

    </head>

    <body>
    1, <a href='a.JSP' onclick='test();'>超级链接 </a>
    2, <input type="button" onclick='test()' value="提交">
    3, <form name="form1"  onsubmIT="return test();">
    内容
    <input type="submIT" value="提交">
    </form>
    </body>

    <a href="xxxx.do?....." target=dolink>连接abcd </a>
    <iframe id=dolink src=about:blank style=display:none> </iframe>

     
    点了上面的那个连接后,dolink帧执行页面处理的事情(xxxx.do?...然传递参数到服务器),页面不会跳转。    .

    最近做的项目,通过绑定在 button 的 onclick 事件的函数提交表单。发现 return false 也是很重要的。比如:

     <input type="submit" onclick="submitAction(); return false;" />

     submitAction 方法里面有提交表单的动作。如果不加 return false,在执行完 submitAction 之后,submit 按钮还会继续执行它的默认事件,就会再次提交表单。这可能就是很多错误的根源。

    的确,return false的含义不是阻止事件继续向顶层元素传播,而是阻止浏览器对事件的默认处理。你可以这样试验:首先将所有的js脚本注释掉,在IE浏览器中尝试拖动一下图片,你会发现鼠标会成为禁止操作的样式,图片是被禁止拖动的,它是浏览器针对mousemove事件所提供的默认行为。return false就是为了去掉这种行为,否则就会出现你描述的中断事件连续执行。

    另外,和return false等效的语句为:window.event.returnValue = false,你可以把return false替换为此语句并进行验证。

    最后说明一下,此种方式只适用于IE浏览器。

    <html>
    <head>
    <script language="javascript">
    function verifyForm(){
    var ass=document.getElementsByName("assetName");
    if(ass[0].value.length==0){
    alert("名称输入为空!");
    return false;
    }

    if(ass[0].value.length>15){
    alert("名称输入长度不能超过15个字符!");
    return false;
    }
    }
    </script>
    </head>
    <body>
    <form name="xx">
    <input name="assetName" type="text"/>
                            <--根据return 返回值的TRUE或FALSE 判定是否提交表单--->
    <input type="submit" onclick="return verifyForm()"/>
    </form>
    </body>
    </html>

    潜水看了众大虾的精彩帖子,今也贡献一点心得。其闻共欣赏,疑义相与析。有不对之处请不吝拍砖。

    众所周知,在表单中加上onsubmit="return false;"可以阻止表单提交。
    下面是简单的一小段代码:

    view plaincopy to clipboardprint?
    <form action="index.jsp" method="post" onsubmit="submitTest();;">  
        <INPUT value="www">  
        <input type="submit" value="submit">  
    </form>  
     
    <SCRIPT LANGUAGE="JavaScript">  
    <!--  
        function submitTest(); {  
            // 一些逻辑判断  
         return false;  
        }  
    //-->  
    </SCRIPT> 

    <form action="index.jsp" method="post" onsubmit="submitTest();;">
        <INPUT value="www">
        <input type="submit" value="submit">
    </form>

    <SCRIPT LANGUAGE="JavaScript">
    <!--
        function submitTest(); {
            // 一些逻辑判断
         return false;
        }
    //-->
    </SCRIPT>
    大家判断像上面的写法,点击submit按钮该表单是否提交?

    若答案为是,就不用往下看了。

    若答案为否,错了。实际情况是表单正常提交,若想它不提交,应该将

    view plaincopy to clipboardprint?
    <form action="index.jsp" method="post" onsubmit="submitTest();;"> 

    <form action="index.jsp" method="post" onsubmit="submitTest();;">改为

    view plaincopy to clipboardprint?
    <form action="index.jsp" method="post" onsubmit="return submitTest();;"> 

    <form action="index.jsp" method="post" onsubmit="return submitTest();;">

    为何?

    原来onsubmit属性就像是<form>这个html对象的一个方法名,其值(一字符串)就是其方法体,默认返回true;

    和Java一样,在该方法体中你可以写任意多个语句,包括内置函数和自定义函数,如

    view plaincopy to clipboardprint?
    onsubmit="  
        alert('haha');; // 内置函数   
        submitTest();;  // 自定义函数  
        alert(this.tagName);; // 用到了this关键词  
        ......(任意多条语句);      
        return false;  

    onsubmit="
        alert('haha');; // 内置函数
        submitTest();;  // 自定义函数
        alert(this.tagName);; // 用到了this关键词
        ......(任意多条语句);   
        return false;
    "
    就相当于

    view plaincopy to clipboardprint?
    Form.prototype.onsubmit = function(); {  
        alert('haha');; // 内置函数  
        submitTest();;  // 自定义函数  
        alert(this.tagName);; // 用到了this关键词  
        ......(任意多条语句);      
        return false;  
    }; 

    Form.prototype.onsubmit = function(); {
        alert('haha');; // 内置函数
        submitTest();;  // 自定义函数
        alert(this.tagName);; // 用到了this关键词
        ......(任意多条语句);   
        return false;
    };
    这样的话你就覆写了(override)其默认方法(默认返回true)
    大家注意到方法体中可以用this这个关键词,这里即代表了<form>的对象实例。

    经过这样的分析后,以上情况就不难理解了:

    view plaincopy to clipboardprint?
    <form action="index.jsp" method="post" onsubmit="submitTest();;"> 

    <form action="index.jsp" method="post" onsubmit="submitTest();;">这样写,override方法的效果为:

    view plaincopy to clipboardprint?
    Form.prototype.onsubmit = function(); {  
        submitTest();;  
    }; 

    Form.prototype.onsubmit = function(); {
        submitTest();;
    };
    在这里submitTest()虽然返回false,但我们只执行了此函数,没有对其结果进行任何处理。而

    view plaincopy to clipboardprint?
    <form action="index.jsp" method="post" onsubmit="return submitTest();;"> 

    <form action="index.jsp" method="post" onsubmit="return submitTest();;">
    override方法的效果为:

    view plaincopy to clipboardprint?
    Form.prototype.onsubmit = function(); {  
        return submitTest();;  
    }; 

    Form.prototype.onsubmit = function(); {
        return submitTest();;
    };
    这样,我们利用到了它的返回值,达到了预期效果。
    这样理解的话我想印象会深刻得多,就不易出错了

    结论:
    我们可以用Java里的思维方式来思考模拟JavaScript中的类似情况(JavaScript中基于prototype的面向对象技术也确实是这样做的),但他们毕竟还是有本质上的区别,如Java是强类型的,有严格的语法限制,而JavaScript是松散型的。象上述方法:

    view plaincopy to clipboardprint?
    Form.prototype.onsubmit = function(); {    
    }; 

    Form.prototype.onsubmit = function(); { 
    };
    既可以有返回值,又可以没有返回值,在Java里是通不过的,毕竟Java里面不能靠方法的返回值不同来重载(overload)方法,而JavaScript中的重载要松散得多。

    posted @ 2009-06-13 23:52 jiafang83 阅读(1336) | 评论 (0)编辑 收藏

    一、 简单的对比

    request.getParameter用的比较多,相对熟悉

    request.getParameterValues(String   name)是获得如checkbox类(名字相同,但值有多个)的数据。   接收数组变量 ,如checkobx类型    
    request.getParameter(String   name)是获得相应名的数据,如果有重复的名,则返回第一个的值 . 接收一般变量 ,如text类型

    例:

    1. 三个名字相同的text标签


    <input type="text" name="test" value="1" />
    <input type="text" name="test" value="2" />
    <input type="text" name="test" value="3" />

    request.getParameterValues("test")   ----------------- [1, 2, 3]

    request.getParameter("test")             ------------------ 1

    ${paramValues.test}

    ${param.test}

    2. checkbox

     <input type="checkbox" name="habit" value="read">看书

     <input type="checkbox" name="habit" value="movie">电影

     <input type="checkbox" name="habit" value="game">游戏

    request.getParameterValues("habit")

    二、与此相关的话题------隐含对象

    1. JSP隐含对象(Implicit Object)


         所谓隐含对象,是指当编写jsp网页时,不必做任何声明就可以直接使用的对象。 JSP2.0定义了九个隐含对象

    request response pageContext session application out conifg page exception

    这里只提一下request 和 response 两个对象

           request 对象表示客户端请求的内容,比如我们从request中取得了用户输入的内容,实现了javax.servlet.http.HttpServletRequest接口

          response对象表示响应客户端的结果。

    上面我们使用了request的两个方法getParameter 和 getParameterValues,其实request还有其他几个比较重要的方法,这里只涉及几个获取请求参数的方法

    String getParameter(String name)                     取得name的参数值

    String[] getParameterValues(String name)        取得所有name的参数值

    Enumeration getParameterNames()                  取得所有的参数名称

    Map<String, String[]> getParameterMap()        取得request的所有参数的一个映射

    //

    Returns a java.util.Map of the parameters of this request. Request parameters are extra information sent with the request. For HTTP servlets, parameters are contained in the query string or posted form data.
    Returns:
    an immutable java.util.Map containing parameter names as keys and parameter values as map values. The keys in the parameter map are of type String. The values in the parameter map are of type String array.
    //

    response等其他几个隐含对象也有非常重要的身份,有机会专门整理一下,宣扬一下它们的显赫地位。

    2. EL隐含对象

    EL即Experssion Language,自JSP2.0后正式成为JSP的标准规范之一,支持Servlet2.4/JSP2.0的Container也就相应的支持EL语法。

    一个常见的形式如,<c:out value="${ 3 + 7 * 4}" />

    EL的隐藏对象有11个 PageContext PageScope RequestScope sessionScope applicationScope

    param paramValues header headerValues cookie initParam

    其中param 和 paramValues即对相应ServletRequest.getParameter(String name)和ServletRequest.getParameterValues(String name)

     

    转载:http://blog.csdn.net/moreorless/archive/2009/05/18/4199677.aspx

    posted @ 2009-06-12 14:53 jiafang83 阅读(737) | 评论 (0)编辑 收藏

    转载:http://www.sucai.com/Tech/List2/17830.htm

    javascript是弱类型的语言,所以强制类型转换还是比较重要的,下面看一下它的几个强制转换的函数:

    1. Boolean(value):把值转换成Boolean类型;

    2. Nnumber(value):把值转换成数字(整型或浮点数);

    3. String(value):把值转换成字符串。

    我们先来看Boolean():在要转换的值为“至少有一字符的字符串”、“非0的数字”或“对象”,那么Boolean()将返回true,如果要转换的值为“空字符串”、“数字0”、“undefined”,“null”这些话,那么Boolean()会返回false。你可以用以下代码来测试

    var t1 = Boolean("");//返回false,空字符串
    var t2 = Boolean("s");//返回true,非空字符串
    var t3 = Boolean(0);//返回false,数字0
    var t3 = Boolean(1),t4 = Boolean(-1);//返回true,非0数字
    var t5 = Boolean(null),t6 = Boolean(undefined);//返回false
    var t7 = Boolean(new Object());//返回true,对象

    再来看看Number():Number()与parseInt()和parseFloat()类似,它们区别在于Number()转换是整个值,而parseInt()和parseFloat()则可以只转换开头的数字部分,例如:Number("1.2.3"),Number("123abc")会返回NaN,而parseInt("1.2.3")返回1、parseInt("123abc")返回123、parseFloat("1.2.3")返回1.2、parseFloat("123abc")返回123。Number()会先判断要转换的值能否被完整的转换,然后再判断是调用parseInt()或parseFloat()。下面列了一些值调用Number()之后的结果:

    Number(false)  0
    Number(true)  1
    Number(undefined)  NaN
    Number(null)  0
    Number("1.2")  1.2

    Number("12")  12
    Number("1.2.3")  NaN
    Number(new Object())  NaN
    Number(123)  123

    最后是String():这个以比较简单了,它可以把所有类型的数据转换成字符串,如:String(false)---"false"、String(1)---"1"。它和toString()方法有些不同,区别在于:

    var t1 = null;
    var t2 = String(t1);//t2的值 "null"
    var t3 = t1.toString();//这里会报错
    var t4;
    var t5 = String(t4);//t5的值 "undefined"
    var t6 = t4.toString();//这里会报错

    posted @ 2009-06-09 16:03 jiafang83 阅读(9620) | 评论 (2)编辑 收藏
         摘要:   阅读全文
    posted @ 2009-06-08 14:28 jiafang83 阅读(2180) | 评论 (3)编辑 收藏
         摘要:   阅读全文
    posted @ 2009-06-05 15:52 jiafang83 阅读(21681) | 评论 (0)编辑 收藏
         摘要:   阅读全文
    posted @ 2009-06-02 16:58 jiafang83 阅读(1737) | 评论 (0)编辑 收藏
         摘要:   阅读全文
    posted @ 2009-06-02 16:50 jiafang83 阅读(1558) | 评论 (0)编辑 收藏
    转载:http://www.javaeye.com/topic/53526

    1、使用JdbcTemplate的execute()方法执行SQL语句
    Java代码 复制代码
    1. jdbcTemplate.execute("CREATE TABLE USER (user_id integer, name varchar(100))");  

    2、如果是UPDATE或INSERT,可以用update()方法。
    Java代码 复制代码
    1. jdbcTemplate.update("INSERT INTO USER VALUES('"  
    2.            + user.getId() + "', '"  
    3.            + user.getName() + "', '"  
    4.            + user.getSex() + "', '"  
    5.            + user.getAge() + "')");  

    3、带参数的更新
    Java代码 复制代码
    1. jdbcTemplate.update("UPDATE USER SET name = ? WHERE user_id = ?"new Object[] {name, id});  

    Java代码 复制代码
    1. jdbcTemplate.update("INSERT INTO USER VALUES(?, ?, ?, ?)"new Object[] {user.getId(), user.getName(), user.getSex(), user.getAge()});  

    4、使用JdbcTemplate进行查询时,使用queryForXXX()等方法
    Java代码 复制代码
    1. int count = jdbcTemplate.queryForInt("SELECT COUNT(*) FROM USER");  


    Java代码 复制代码
    1. String name = (String) jdbcTemplate.queryForObject("SELECT name FROM USER WHERE user_id = ?"new Object[] {id}, java.lang.String.class);  


    Java代码 复制代码
    1. List rows = jdbcTemplate.queryForList("SELECT * FROM USER");  


    Java代码 复制代码
    1. List rows = jdbcTemplate.queryForList("SELECT * FROM USER");   
    2. Iterator it = rows.iterator();   
    3. while(it.hasNext()) {   
    4.     Map userMap = (Map) it.next();   
    5.     System.out.print(userMap.get("user_id") + "\t");   
    6.     System.out.print(userMap.get("name") + "\t");   
    7.     System.out.print(userMap.get("sex") + "\t");   
    8.     System.out.println(userMap.get("age") + "\t");   
    9. }  


       JdbcTemplate将我们使用的JDBC的流程封装起来,包括了异常的捕捉、SQL的执行、查询结果的转换等等。spring大量使用Template Method模式来封装固定流程的动作,XXXTemplate等类别都是基于这种方式的实现。
        除了大量使用Template Method来封装一些底层的操作细节,spring也大量使用callback方式类回调相关类别的方法以提供JDBC相关类别的功能,使传统的JDBC的使用者也能清楚了解spring所提供的相关封装类别方法的使用。

    JDBC的PreparedStatement
    Java代码 复制代码
    1. final String id = user.getId();   
    2. final String name = user.getName();   
    3. final String sex = user.getSex() + "";   
    4. final int age = user.getAge();   
    5.   
    6. jdbcTemplate.update("INSERT INTO USER VALUES(?, ?, ?, ?)",   
    7.                      new PreparedStatementSetter() {   
    8.                          public void setValues(PreparedStatement ps) throws SQLException {   
    9.                              ps.setString(1, id);   
    10.                              ps.setString(2, name);             
    11.                              ps.setString(3, sex);   
    12.                              ps.setInt(4, age);   
    13.                          }   
    14.                      });  


    Java代码 复制代码
    1. final User user = new User();   
    2. jdbcTemplate.query("SELECT * FROM USER WHERE user_id = ?",   
    3.                     new Object[] {id},   
    4.                     new RowCallbackHandler() {   
    5.                         public void processRow(ResultSet rs) throws SQLException {   
    6.                             user.setId(rs.getString("user_id"));   
    7.                             user.setName(rs.getString("name"));   
    8.                             user.setSex(rs.getString("sex").charAt(0));   
    9.                             user.setAge(rs.getInt("age"));   
    10.                         }   
    11.                     });  




    Java代码 复制代码
    1. class UserRowMapper implements RowMapper {   
    2.     public Object mapRow(ResultSet rs, int index) throws SQLException {   
    3.         User user = new User();   
    4.   
    5.         user.setId(rs.getString("user_id"));   
    6.         user.setName(rs.getString("name"));   
    7.         user.setSex(rs.getString("sex").charAt(0));   
    8.         user.setAge(rs.getInt("age"));   
    9.   
    10.         return user;   
    11.     }   
    12. }   
    13.   
    14. public List findAllByRowMapperResultReader() {   
    15.     String sql = "SELECT * FROM USER";   
    16.     return jdbcTemplate.query(sql, new RowMapperResultReader(new UserRowMapper()));   
    17. }  


    在getUser(id)里面使用UserRowMapper
    Java代码 复制代码
    1. public User getUser(final String id) throws DataAccessException {   
    2.     String sql = "SELECT * FROM USER WHERE user_id=?";   
    3.     final Object[] params = new Object[] { id };   
    4.     List list = jdbcTemplate.query(sql, params, new RowMapperResultReader(new UserRowMapper()));   
    5.   
    6.     return (User) list.get(0);   
    7. }  


    网上收集
    org.springframework.jdbc.core.PreparedStatementCreator 返回预编译SQL   不能于Object[]一起用
    Java代码 复制代码
    1. public PreparedStatement createPreparedStatement(Connection con) throws SQLException {   
    2.  return con.prepareStatement(sql);   
    3. }  

    1.增删改
    org.springframework.jdbc.core.JdbcTemplate   类(必须指定数据源dataSource)
    Java代码 复制代码
    1. template.update("insert into web_person values(?,?,?)",Object[]);  

      或
    Java代码 复制代码
    1. template.update("insert into web_person values(?,?,?)",new PreparedStatementSetter(){ 匿名内部类 只能访问外部最终局部变量   
    2.   
    3.  public void setValues(PreparedStatement ps) throws SQLException {   
    4.   ps.setInt(index++,3);   
    5. });  

    org.springframework.jdbc.core.PreparedStatementSetter 接口 处理预编译SQL
    Java代码 复制代码
    1. public void setValues(PreparedStatement ps) throws SQLException {   
    2.  ps.setInt(index++,3);   
    3. }  

    2.查询JdbcTemplate.query(String,[Object[]/PreparedStatementSetter],RowMapper/RowCallbackHandler)
    org.springframework.jdbc.core.RowMapper   记录映射接口  处理结果集
    Java代码 复制代码
    1. public Object mapRow(ResultSet rs, int arg1) throws SQLException {   int表当前行数   
    2.   person.setId(rs.getInt("id"));   
    3. }   
    4. List template.query("select * from web_person where id=?",Object[],RowMapper);  

    org.springframework.jdbc.core.RowCallbackHandler  记录回调管理器接口 处理结果集
    Java代码 复制代码
    1. template.query("select * from web_person where id=?",Object[],new RowCallbackHandler(){   
    2.  public void processRow(ResultSet rs) throws SQLException {   
    3.   person.setId(rs.getInt("id"));   
    4. });  
    posted @ 2009-05-26 15:06 jiafang83| 编辑 收藏

        DecimalFormatNumberFormat 的一个具体子类,用于格式化十进制数字。该类设计有各种功能,使其能够分析和格式化任意语言环境中的数,包括对西方语言、阿拉伯语和印度语数字的支持。它还支持不同类型的数,包括整数 (123)、定点数 (123.4)、科学记数法表示的数 (1.23E4)、百分数 (12%) 和金额 ($123)。所有这些内容都可以本地化。

     1截取double类型的小数位:
     2public class Test {
     3   public static void main(String[] args){
     4      double a = 1.999999999999;
     5      //保留a的两位小数,注意不是四舍五入
     6      DecimalFormat df = new DecimalForma("#.00");
     7      a = Double.parseDouble(df.format(a));//format方法返回的是字符串类型
     8      System.out.println(a);
     9   }

    10}
    posted @ 2009-04-16 09:04 jiafang83 阅读(241) | 评论 (0)编辑 收藏
    转载:
    1.web打印控件的三种实现方法:http://www.blogjava.net/midstr/archive/2009/03/13/256597.html   ----“岁月如歌”的博客
    2.IEWebBrowser组件的execWB方法:http://dev.csdn.net/article/16/16938.shtm  ------haley_hj 的 Blog
    3.WEB打印大全:http://www.fangxun.net/tech/techfile/prog/asp/200610/2612.htm
    4.14个经典的JavaScript代码:http://www.vikecn.com/Skins/Skin3/blogview.asp?153078-27932.html
    posted @ 2009-04-15 14:42 jiafang83| 编辑 收藏
    转载:http://hi.baidu.com/xeelytech/blog/item/b8e42cfdac841d1508244d42.html



    iframe 父窗口和子窗口的调用方法
    父窗口调用子窗口
    iframe_name.iframe_document_object.object_attribute = attribute_value
    例子:onClick="iframe_text.myH1.innerText='http://www.pint.com';"
    子窗口调用父窗口parent.parent_document_object.object_attribute = attribute_value
    例子:onclick="parent.myH1.innerText='http://www.pint.com';"
    上面在IE下没有问题,但在firefox下不正常。在firefox下,应该是
    父窗口调用子窗口
    window.frames["iframe_name"].document.getElementById("iframe_document_object"-).object_attribute = attribute_value
    例子
    window.frames["iframe_text"].document.getElementById("myH1").innerHTML= "http://www.pint.com";
    子窗口调用父窗口
    parent.document.getElementById("parent_document_object").object_attribute = attribute_value
    例子
    parent.document.getElementById("myH1").innerHTML = "http://www.adsf.com";

     

    完整例子:
    start.html

    <html>
    <script type="text/javascript">
    function b(){
        alert(
    "父窗口编辑子窗口的内容。。。");
        window.frames[
    "floater"].document.getElementById("bb").innerHTML="父窗口改变子窗口内容";
        
    //下句只适合IE浏览器
        //floater.bb.innerText="父窗口修改子窗口内容。。。";
    }

    </script>
    <body>
    <IFRAME name="floater" src="three.html" width=1000 height=600 hspace=20 vspace=20 align=right frameborder=1>
    </IFRAME><BR>
    <img src="星球大战.jpg" /><br>
    <id="aa" href="one.html" target="floater">Show one.htm</A><P> 
    <form id="a" action="#" method="post">
    <input type=button value="修改子窗口内容" onclick="b()">
    </form>
    </body>
    </html>

    one.html

    <html>
    one.html
    </html>

    three.html

    <html>
    <script typt="text/javascript">
    function a(){
        alert(
    "子窗口编辑父窗口内容parent表示父窗口");
        
    //下句只适合IE浏览器
        //parent.aa.innerText="ppppppppppppp";
        parent.document.getElementById("aa").innerHTML="修改父窗口内容";
        
    //parent.frames["iframe的名称"].document.getElementById("aa").innerText="修改父窗口内容。。。。";
        //子窗口修改父窗口的另一个子窗口的内容
    }

    </script>
    <body onload="a()">
    <h1 id="bb">改变父窗口的元素值。</h1>
    </body>
    </html>
    posted @ 2009-03-29 15:53 jiafang83| 编辑 收藏
    转载:http://hi.baidu.com/wukongafei/blog/item/9e92e800923eca14728b6596.html

    把subversion加入windows服务
    sc create svnserver binPath= "E:\Program Files\Subversion\bin\svnserve.exe --service -r E:\cjf\repository" DisplayName= "subversion" depend= Tcpip start= auto
    posted @ 2009-03-23 09:01 jiafang83| 编辑 收藏
    转载:
    http://blog.sina.com.cn/s/blog_49ee6e040100awbe.html

    posted @ 2009-03-23 09:00 jiafang83| 编辑 收藏

     

     1import java.util.ArrayList;
     2
     3public class Test01 {
     4    
     5    Test01() { }
     6
     7    /**
     8     * 除去字符串数组中重复次数超过整数n的数组元素.使用时请使用try{}catch(){}包含.或是使用throws声明抛出异常
     9     */

    10    public String[] execute(String[] args, int n) throws Exception {
    11        //Arrays.sort(args); // 此行代码可以不使用,使用得话会使数组工整,排序数据.
    12        ArrayList<String> list = new ArrayList<String>(args.length);
    13        //count变量,记录数组元素的重复次数
    14        int count = 0;
    15        for (int i = 0; i < args.length; i++{
    16            count = 0;
    17            for (int j = 0; j < args.length; j++{
    18                if (args[i].equals(args[j])) {
    19                    count++;
    20                }

    21            }

    22            //把重复次数小于等于n的数组元素放进集合List中
    23            if (count <= n) {
    24                list.add(args[i]);
    25            }

    26
    27        }

    28        //新建一个数组,数组的长度为集合list的长度
    29        String[] retStrs = new String[list.size()];
    30        //然后把集合list的元素按照顺序赋给新建的数组
    31        for (int i = 0; i < list.size(); i++{
    32            retStrs[i] = (String) list.get(i);
    33        }

    34        //返回该数组
    35        return retStrs;
    36    }

    37
    38    public static void main(String[] arguments) throws Exception {
    39
    40        String[] t = new Test01().execute(new String[] "aaaaa""ccccc",
    41                "aaaaa""aaaaa""ccccc""ddddd""ddddd""eeeee""aaaaa",
    42                "fffff""ddddd""fffff""ddddd" }
    3);
    43        for (String x : t) {
    44            System.out.println(x);
    45        }

    46    }

    47}

     

    posted @ 2009-03-11 21:17 jiafang83 阅读(672) | 评论 (0)编辑 收藏
    转载:http://zhidao.baidu.com/question/35054792.html

    Eclipse插件的安装有两种方法

    1、在eclipse的主目录(ECLIPSE_HOME,比如在我的机器上安装的目录是:D:\JavaDev\3.1)有一个plugins的目录,这种方法的插件安装非常简单,只要将插件copy到这个目录下就可以了。比如我有一个weblogic的插件(bea站点上可以下载),解压缩之后得到得到一个目录:【com.bea.eclipse.weblogic_1.1.1】,我就将这个目录直接放到%ECLIPSE_HOME%\plugins目录下,重新启动eclipse之后就看到Run->“Start Weblogic”的菜单。安装之后,weblogic插件的全路径为:D:\JavaDev\3.1\plugins\com.bea.eclipse.weblogic_1.1.1]

    2、在eclipse目录(ECLIPSE_HOME)下创建一个links目录,然后将你自己的插件放在你想放的任何地方,这个时候你放插件的目录我称她为插件目录(PLUGIN_HOME),然后在你的%ECLIPSE_HOME%\links\目录下创建一个link文件,比如我要安装一个vss插件,我就在我的links目录下创建了:VSS_1.6.1.link文件。而这个VSS_1.6.1.link文件则是指向的我的插件目录(PLUGIN_HOME,比如在我的机器上插件目录为D:\JavaDev\plugins)。VSS_1.6.1.link文件的内容是:

    path=D:\\JavaDev\\plugins\\vssplugin_1.6.1

    第二种安装插件的时候需要注意,如果你是一个单独的jar文件,则最好在link文件指定的目录下创建这样级别的目录:eclipse\plugins\xxx.xxx(插件名称和版本号),然后将jar文件放在这个目录下即可。比如vss插件在我的机器上的目录是D:\JavaDev\plugins\vssplugin_1.6.1\eclipse\plugins\org.vssplugin_1.6.1,下有一个文件:vssplugin.jar

    两种方法的插件安装之后需要重新启动eclipse才能看到插件。如果某一个插件已经安装了想要重新安装,只要将文件替换或者修改link文件的路径即可。如果发现认不到插件,可能是你的插件不支持你的当前eclipse版本,请检查。也有可能是系统配置引起的,我出现过一次,我的解决方法是将ECLIPSE_HOME下的configuration目录下的所有文件删除,剩下config.ini文件。

    13.Eclipse插件使用links目录的用法:
    假设把插件安装在d:\myplugin目录中,则myplugin的目录结构一定要是这样的:
    d:\\myplugin\\eclipse\\plugins\\插件 及 d:\\myplugin\\eclipse\\features\\插件
    例如安装EclipseME插件到d:\myplugin目录中,则目录结构

    d:\\myplugin\\eclipse\\plugins\\eclipseme_0.4.5。
    再假设eclipse安装在d:\eclipse目录中,则在eclipse目录中创建名称为links的目录,在links目

    录中建立一个link文件,比如myplugin.link,该文件内容为path=d:\\myplugin。
    启动eclipse,插件即安装上了,如果想暂时不启动插件,只需把myplugin.link文件删除即可。
    补充说明:
    1. 插件可以分别安装在多个自定义的目录中。
    2. 一个自定义目录可以安装多个插件。
    3. link文件的文件名及扩展名可以取任意名称,比如myplugin.txt,goodplugin都可以。
    4. link文件可以有多行path=插件目录,对应多个自定义插件目录,每一行的path参数都将生效。
    5. 在links目录也可以有多个link文件,每个link文件中的path参数都将生效。
    6. 插件目录可以使用相对路径,如果我们把myplugin目录创建在eclipse安装目录中,如上例中的

    d:\eclipse目录中,则只需设置path=myplugin即可。
    posted @ 2009-02-18 21:36 jiafang83 阅读(134) | 评论 (0)编辑 收藏
    http://hi.baidu.com/menglinxi%5Fa/blog/item/cf492e4532f85821cffca383.html

    1. 介绍

    1)DOM(JAXP Crimson解析器)
            DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准。DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作。由于它是基于信息层次的,因而DOM被认为是基于树或基于对象的。DOM以及广义的基于树的处理具有几个优点。首先,由于树在内存中是持久的,因此可以修改它以便应用程序能对数据和结构作出更改。它还可以在任何时候在树中上下导航,而不是像SAX那样是一次性的处理。DOM使用起来也要简单得多。

    2)SAX

            SAX处理的优点非常类似于流媒体的优点。分析能够立即开始,而不是等待所有的数据被处理。而且,由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优点。事实上,应用程序甚至不必解析整个文档;它可以在某个条件得到满足时停止解析。一般来说,SAX还比它的替代者DOM快许多。
      选择DOM还是选择SAX? 对于需要自己编写代码来处理XML文档的开发人员来说, 选择DOM还是SAX解析模型是一个非常重要的设计决策。 DOM采用建立树形结构的方式访问XML文档,而SAX采用的事件模型。

      DOM解析器把XML文档转化为一个包含其内容的树,并可以对树进行遍历。用DOM解析模型的优点是编程容易,开发人员只需要调用建树的指令,然后利用navigation APIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用DOM解析器的时候需要处理整个XML文档,所以对性能和内存的要求比较高,尤其是遇到很大的XML文件的时候。由于它的遍历能力,DOM解析器常用于XML文档需要频繁的改变的服务中。

      SAX解析器采用了基于事件的模型,它在解析XML文档的时候可以触发一系列的事件,当发现给定的tag的时候,它可以激活一个回调方法,告诉该方法制定的标签已经找到。SAX对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的tag。特别是当开发人员只需要处理文档中所包含的部分数据时,SAX这种扩展能力得到了更好的体现。但用SAX解析器的时候编码工作会比较困难,而且很难同时访问同一个文档中的多处不同数据。

    3)JDOM          http://www.jdom.org/

              JDOM的目的是成为Java特定文档模型,它简化与XML的交互并且比使用DOM实现更快。由于是第一个Java特定模型,JDOM一直得到大力推广和促进。正在考虑通过“Java规范请求JSR-102”将它最终用作“Java标准扩展”。从2000年初就已经开始了JDOM开发。

      JDOM与DOM主要有两方面不同。首先,JDOM仅使用具体类而不使用接口。这在某些方面简化了API,但是也限制了灵活性。第二,API大量使用了Collections类,简化了那些已经熟悉这些类的Java开发者的使用。

      JDOM文档声明其目的是“使用20%(或更少)的精力解决80%(或更多)Java/XML问题”(根据学习曲线假定为20%)。JDOM对于大多数Java/XML应用程序来说当然是有用的,并且大多数开发者发现API比DOM容易理解得多。JDOM还包括对程序行为的相当广泛检查以防止用户做任何在XML中无意义的事。然而,它仍需要您充分理解XML以便做一些超出基本的工作(或者甚至理解某些情况下的错误)。这也许是比学习DOM或JDOM接口都更有意义的工作。

      JDOM自身不包含解析器。它通常使用SAX2解析器来解析和验证输入XML文档(尽管它还可以将以前构造的DOM表示作为输入)。它包含一些转换器以将JDOM表示输出成SAX2事件流、DOM模型或XML文本文档。JDOM是在Apache许可证变体下发布的开放源码。

    4)DOM4J http://dom4j.sourceforge.net/
                
            虽然DOM4J代表了完全独立的开发结果,但最初,它是JDOM的一种智能分支。它合并了许多超出基本XML文档表示的功能,包括集成的XPath支持、XML Schema支持以及用于大文档或流化文档的基于事件的处理。它还提供了构建文档表示的选项,它通过DOM4J API和标准DOM接口具有并行访问功能。从2000下半年开始,它就一直处于开发之中。

      为支持所有这些功能,DOM4J使用接口和抽象基本类方法。DOM4J大量使用了API中的Collections类,但是在许多情况下,它还提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是,虽然DOM4J付出了更复杂的API的代价,但是它提供了比JDOM大得多的灵活性。

      在添加灵活性、XPath集成和对大文档处理的目标时,DOM4J的目标与JDOM是一样的:针对Java开发者的易用性和直观操作。它还致力于成为比JDOM更完整的解决方案,实现在本质上处理所有Java/XML问题的目标。在完成该目标时,它比JDOM更少强调防止不正确的应用程序行为。

      DOM4J是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML,特别值得一提的是连Sun的JAXM也在用DOM4J。

    2.. 比较

    1)DOM4J性能最好,连Sun的JAXM也在用DOM4J。目前许多开源项目中大量采用DOM4J,例如大名鼎鼎的Hibernate也用DOM4J来读取XML配置文件。如果不考虑可移植性,那就采用DOM4J.

    2)JDOM和DOM在性能测试时表现不佳,在测试10M文档时内存溢出。在小文档情况下还值得考虑使用DOM和JDOM。虽然JDOM的开发者已经说明他们期望在正式发行版前专注性能问题,但是从性能观点来看,它确实没有值得推荐之处。另外,DOM仍是一个非常好的选择。DOM实现广泛应用于多种编程语言。它还是许多其它与XML相关的标准的基础,因为它正式获得W3C推荐(与基于非标准的Java模型相对),所以在某些类型的项目中可能也需要它(如在JavaScript中使用DOM)。

    3)SAX表现较好,这要依赖于它特定的解析方式-事件驱动。一个SAX检测即将到来的XML流,但并没有载入到内存(当然当XML流被读入时,会有部分文档暂时隐藏在内存中)。

    3. 四种xml操作方式的基本使用方法

    xml文件:

    <?xml version="1.0" encoding="utf-8" ?>
    <Result>
       <VALUE>
           <NO DATE="2005">A1</NO>
           <ADDR>GZ</ADDR>
       </VALUE>
       <VALUE>
           <NO DATE="2004">A2</NO>
           <ADDR>XG</ADDR>
    </VALUE>
    </Result>

    1)DOM

    import java.io.*;
    import java.util.*;
    import org.w3c.dom.*;
    import javax.xml.parsers.*;

    public class MyXMLReader{
     public static void main(String arge[]){

      long lasting =System.currentTimeMillis();
      try{
       File f=new File("data_10k.xml");
       DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
       DocumentBuilder builder=factory.newDocumentBuilder();
       Document doc = builder.parse(f);
       NodeList nl = doc.getElementsByTagName("VALUE");
       for (int i=0;i<nl.getLength();i++){
        System.out.print("车牌号码:" + doc.getElementsByTagName("NO").item(i).getFirstChild().getNodeValue());
        System.out.println("车主地址:" + doc.getElementsByTagName("ADDR").item(i).getFirstChild().getNodeValue());
       }
      }catch(Exception e){
       e.printStackTrace();
    }

    2)SAX

    import org.xml.sax.*;
    import org.xml.sax.helpers.*;
    import javax.xml.parsers.*;

    public class MyXMLReader extends DefaultHandler {

     java.util.Stack tags = new java.util.Stack();
     public MyXMLReader() {
      super();
       }

     public static void main(String args[]) {
      long lasting = System.currentTimeMillis();
      try {
       SAXParserFactory sf = SAXParserFactory.newInstance();
       SAXParser sp = sf.newSAXParser();
       MyXMLReader reader = new MyXMLReader();
       sp.parse(new InputSource("data_10k.xml"), reader);
      } catch (Exception e) {
       e.printStackTrace();
      }

      System.out.println("运行时间:" + (System.currentTimeMillis() - lasting) + "毫秒");}
      public void characters(char ch[], int start, int length) throws SAXException {
      String tag = (String) tags.peek();
      if (tag.equals("NO")) {
       System.out.print("车牌号码:" + new String(ch, start, length));
        }
        if (tag.equals("ADDR")) {
      System.out.println("地址:" + new String(ch, start, length));
        }
       }

      public void startElement(String uri,String localName,String qName,Attributes attrs) {
      tags.push(qName);}
    }

    3) JDOM

    import java.io.*;
    import java.util.*;
    import org.jdom.*;
    import org.jdom.input.*;

    public class MyXMLReader {

     public static void main(String arge[]) {
      long lasting = System.currentTimeMillis();
      try {
       SAXBuilder builder = new SAXBuilder();
       Document doc = builder.build(new File("data_10k.xml"));
       Element foo = doc.getRootElement();
       List allChildren = foo.getChildren();
       for(int i=0;i<allChildren.size();i++) {
        System.out.print("车牌号码:" + ((Element)allChildren.get(i)).getChild("NO").getText());
        System.out.println("车主地址:" + ((Element)allChildren.get(i)).getChild("ADDR").getText());
       }
      } catch (Exception e) {
       e.printStackTrace();
    }

    }

    4)DOM4J

    import java.io.*;
    import java.util.*;
    import org.dom4j.*;
    import org.dom4j.io.*;

    public class MyXMLReader {

     public static void main(String arge[]) {
      long lasting = System.currentTimeMillis();
      try {
       File f = new File("data_10k.xml");
       SAXReader reader = new SAXReader();
       Document doc = reader.read(f);
       Element root = doc.getRootElement();
       Element foo;
       for (Iterator i = root.elementIterator("VALUE"); i.hasNext();) {
        foo = (Element) i.next();
        System.out.print("车牌号码:" + foo.elementText("NO"));
        System.out.println("车主地址:" + foo.elementText("ADDR"));
       }
      } catch (Exception e) {
       e.printStackTrace();
        }
    }

    posted @ 2009-02-18 21:27 jiafang83 阅读(333) | 评论 (1)编辑 收藏
    http://hi.baidu.com/lc2tp/blog/item/477c3601aac1ca011c9583dc.html

    要使用dom4j读写XML文档,需要先下载dom4j包,dom4j官方网站在 http://www.dom4j.org/
    目前最新dom4j包下载地址:http://nchc.dl.sourceforge.net/sourceforge/dom4j/dom4j-1.6.1.zip

    解开后有两个包,仅操作XML文档的话把dom4j-1.6.1.jar加入工程就可以了,如果需要使用XPath的话还需要加入包jaxen-1.1-beta-7.jar.

    以下是相关操作:

    一.Document对象相关

    1.读取XML文件,获得document对象.
                SAXReader reader = new SAXReader();
                Document document = reader.read(new File("input.xml"));

    2.解析XML形式的文本,得到document对象.
                String text = "<members></members>";
                Document document = DocumentHelper.parseText(text);
    3.主动创建document对象.
                Document document = DocumentHelper.createDocument();
                Element root = document.addElement("members");// 创建根节点
    二.节点相关

    1.获取文档的根节点.
    Element rootElm = document.getRootElement();
    2.取得某节点的单个子节点.
    Element memberElm=root.element("member");// "member"是节点名
    3.取得节点的文字
    String text=memberElm.getText();
    也可以用:
    String text=root.elementText("name");这个是取得根节点下的name字节点的文字.

    4.取得某节点下名为"member"的所有字节点并进行遍历.
    List nodes = rootElm.elements("member");

    for (Iterator it = nodes.iterator(); it.hasNext();) {
       Element elm = (Element) it.next();
       // do something
    }
    5.对某节点下的所有子节点进行遍历.
                for(Iterator it=root.elementIterator();it.hasNext();){
                    Element element = (Element) it.next();
                    // do something
                }
    6.在某节点下添加子节点.
    Element ageElm = newMemberElm.addElement("age");
    7.设置节点文字.
    ageElm.setText("29");
    8.删除某节点.
    parentElm.remove(childElm);// childElm是待删除的节点,parentElm是其父节点
    三.属性相关.
    1.取得某节点下的某属性
                Element root=document.getRootElement();   
                Attribute attribute=root.attribute("size");// 属性名name
    2.取得属性的文字
                String text=attribute.getText();
    也可以用:
    String text2=root.element("name").attributeValue("firstname");这个是取得根节点下name字节点的属性firstname的值.

    3.遍历某节点的所有属性
                Element root=document.getRootElement();   
                for(Iterator it=root.attributeIterator();it.hasNext();){
                    Attribute attribute = (Attribute) it.next();
                    String text=attribute.getText();
                    System.out.println(text);
                }
    4.设置某节点的属性和文字.
    newMemberElm.addAttribute("name", "sitinspring");
    5.设置属性的文字
                Attribute attribute=root.attribute("name");
                attribute.setText("sitinspring");
    6.删除某属性
                Attribute attribute=root.attribute("size");// 属性名name
                root.remove(attribute);
    四.将文档写入XML文件.
    1.文档中全为英文,不设置编码,直接写入的形式.
    XMLWriter writer = new XMLWriter(new FileWriter("output.xml"));
    writer.write(document);
    writer.close();
    2.文档中含有中文,设置编码格式写入的形式.
                OutputFormat format = OutputFormat.createPrettyPrint();
                format.setEncoding("GBK");    // 指定XML编码       
                XMLWriter writer = new XMLWriter(new FileWriter("output.xml"),format);
               
                writer.write(document);
                writer.close();
    五.字符串与XML的转换
    1.将字符串转化为XML
    String text = "<members> <member>sitinspring</member> </members>";
    Document document = DocumentHelper.parseText(text);
    2.将文档或节点的XML转化为字符串.
                SAXReader reader = new SAXReader();
                Document document = reader.read(new File("input.xml"));           
                Element root=document.getRootElement();               
                String docXmlText=document.asXML();
                String rootXmlText=root.asXML();
                Element memberElm=root.element("member");
                String memberXmlText=memberElm.asXML();
    六.使用XPath快速找到节点.
    读取的XML文档示例
    <?xml version="1.0" encoding="UTF-8"?>
    <projectDescription>
    <name>MemberManagement</name>
    <comment></comment>
    <projects>
        <project>PRJ1</project>
        <project>PRJ2</project>
        <project>PRJ3</project>
        <project>PRJ4</project>
    </projects>
    <buildSpec>
        <buildCommand>
          <name>org.eclipse.jdt.core.javabuilder</name>
          <arguments>
          </arguments>
        </buildCommand>
    </buildSpec>
    <natures>
        <nature>org.eclipse.jdt.core.javanature</nature>
    </natures>
    </projectDescription>

    使用XPath快速找到节点project.
    public static void main(String[] args){
        SAXReader reader = new SAXReader();
       
        try{
          Document doc = reader.read(new File("sample.xml"));
         
          List projects=doc.selectNodes("/projectDescription/projects/project");
         
          Iterator it=projects.iterator();
         
          while(it.hasNext()){
            Element elm=(Element)it.next();      
            System.out.println(elm.getText());
          }
         
        }
        catch(Exception ex){
           ex.printStackTrace();
        }
    }

    posted @ 2009-02-18 21:25 jiafang83 阅读(1024) | 评论 (1)编辑 收藏
    转载:http://hi.baidu.com/flyx100/blog/item/ca403e2f8d73233f1f3089a7.html

    Eclipse的编辑功能非常强大,掌握了Eclipse快捷键功能,能够大大提高开发效率。Eclipse中有如下一些和编辑相关的快捷键。
       1. 【ALT+/】
       此快捷键为用户编辑的好帮手,能为用户提供内容的辅助,不要为记不全方法和属性名称犯愁,当记不全类、方法和属性的名字时,多体验一下【ALT+/】快捷键带来的好处吧。

       2. 【Ctrl+O】
       显示类中方法和属性的大纲,能快速定位类的方法和属性,在查找Bug时非常有用。

       3. 【Ctrl+/】
       快速添加注释,能为光标所在行或所选定行快速添加注释或取消注释,在调试的时候可能总会需要注释一些东西或取消注释,现在好了,不需要每行进行重复的注释。

       4. 【Ctrl+D】
       删除当前行,这也是笔者的最爱之一,不用为删除一行而按那么多次的删除键。

       5. 【Ctrl+M】
       窗口最大化和还原,用户在窗口中进行操作时,总会觉得当前窗口小(尤其在编写代码时),现在好了,试试【Ctrl+M】快捷键。

       查看和定位快捷键

       在程序中,迅速定位代码的位置,快速找到Bug的所在,是非常不容易的事,Eclipse提供了强大的查找功能,可以利用如下的快捷键帮助完成查找定位的工作。

       1. 【Ctrl+K】、【Ctrl++Shift+K】
       快速向下和向上查找选定的内容,从此不再需要用鼠标单击查找对话框了。

       2. 【Ctrl+Shift+T】
       查找工作空间(Workspace)构建路径中的可找到Java类文件,不要为找不到类而痛苦,而且可以使用“*”、“?”等通配符。

       3. 【Ctrl+Shift+R】
       和【Ctrl+Shift+T】对应,查找工作空间(Workspace)中的所有文件(包括Java文件),也可以使用通配符。

       4. 【Ctrl+Shift+G】
       查找类、方法和属性的引用。这是一个非常实用的快捷键,例如要修改引用某个方法的代码,可以通过【Ctrl+Shift+G】快捷键迅速定位所有引用此方法的位置。

       5. 【Ctrl+Shift+O】
    快速生成import,当从网上拷贝一段程序后,不知道如何import进所调用的类,试试【Ctrl+Shift+O】快捷键,一定会有惊喜。

       6. 【Ctrl+Shift+F】
       格式化代码,书写格式规范的代码是每一个程序员的必修之课,当看见某段代码极不顺眼时,选定后按【Ctrl+Shift+F】快捷键可以格式化这段代码,如果不选定代码则默认格式化当前文件(Java文件)。

       7. 【ALT+Shift+W】
       查找当前文件所在项目中的路径,可以快速定位浏览器视图的位置,如果想查找某个文件所在的包时,此快捷键非常有用(特别在比较大的项目中)。

       8. 【Ctrl+L】
       定位到当前编辑器的某一行,对非Java文件也有效。

       9. 【Alt+←】、【Alt+→】
       后退历史记录和前进历史记录,在跟踪代码时非常有用,用户可能查找了几个有关联的地方,但可能记不清楚了,可以通过这两个快捷键定位查找的顺序。

       10. 【F3】
    快速定位光标位置的某个类、方法和属性。

       11. 【F4】
       显示类的继承关系,并打开类继承视图。

       调试快捷键

       Eclipse中有如下一些和运行调试相关的快捷键。

       1. 【Ctrl+Shift+B】:在当前行设置断点或取消设置的断点。
       2. 【F11】:调试最后一次执行的程序。
       3. 【Ctrl+F11】:运行最后一次执行的程序。
       4. 【F5】:跟踪到方法中,当程序执行到某方法时,可以按【F5】键跟踪到方法中。
       5. 【F6】:单步执行程序。
       6. 【F7】:执行完方法,返回到调用此方法的后一条语句。
       7. 【F8】:继续执行,到下一个断点或程序结束。

       常用编辑器快捷键

       通常文本编辑器都提供了一些和编辑相关的快捷键,在Eclipse中也可以通过这些快捷键进行文本编辑。
       1. 【Ctrl+C】:复制。
       2. 【Ctrl+X】:剪切。
       3. 【Ctrl+V】:粘贴。
       4. 【Ctrl+S】:保存文件。
       5. 【Ctrl+Z】:撤销。
       6. 【Ctrl+Y】:重复。
       7. 【Ctrl+F】:查找。

       其他快捷键

       Eclipse中还有很多快捷键,无法一一列举,可以通过帮助文档找到它们的使用方式,另外还有几个常用的快捷键如下。
       1. 【Ctrl+F6】:切换到下一个编辑器。
       2. 【Ctrl+Shift+F6】:切换到上一个编辑器。
       3. 【Ctrl+F7】:切换到下一个视图。
       4. 【Ctrl+Shift+F7】:切换到上一个视图。
       5. 【Ctrl+F8】:切换到下一个透视图。
       6. 【Ctrl+Shift+F8】:切换到上一个透视图。

       Eclipse中快捷键比较多,可以通过帮助文档找到所有快捷键的使用,但要掌握所有快捷键的使用是不可能的,也没有必要,如果花点时间熟悉本节列举的快捷键,
    --------------------------------------------------------------------------------------------
    -----------------------------------------------------------------------------------------------
    1几个最重要的快捷键

    代码助手:Ctrl+Space(简体中文操作系统是Alt+/)
    快速修正:Ctrl+1
    单词补全:Alt+/
    打开外部Java文档:Shift+F2

    显示搜索对话框:Ctrl+H
    快速Outline:Ctrl+O
    打开资源:Ctrl+Shift+R
    打开类型:Ctrl+Shift+T
    显示重构菜单:Alt+Shift+T

    上一个/下一个光标的位置:Alt+Left/Right
    上一个/下一个成员(成员对象或成员函数):Ctrl+Shift+Up/Down
    选中闭合元素:Alt+Shift+Up/Down/Left/Right
    删除行:Ctrl+D
    在当前行上插入一行:Ctrl+Shift+Enter
    在当前行下插入一行: Shift+Enter
    上下移动选中的行:Alt+Up/Down


    组织导入:Ctrl+Shift+O

    2 定位
    2.1行内定位
    行末/行首:End/Home
    前一个/后一个单词:Ctrl+Right/Left
    2.2文件内定位
    跳到某行:Ctrl+L
    上下滚屏:Ctrl+Up/Down
    上一个/下一个成员(成员对象或成员函数):Ctrl+Shift+Up/Down
    快速Outline:Ctrl+O
    2.3跨文件定位
    打开声明:F3
    打开资源:Ctrl+Shift+R
    打开类型:Ctrl+Shift+T
    在workspace中搜索选中元素的声明:Ctrl+G
    在workspace中搜索选中的文本:Ctrl+Alt+G
    在workspace中搜索选中元素的引用:Ctrl+Shift+G
    打开调用层次结构:Ctrl+Alt+H
    快速层次结构:Ctrl+T
    反悔:Ctrl+Z
    2.4其它
    上一个/下一个光标所在位置:Alt+Left/Right
    上一个编辑的位置:Ctrl+Q

     

    3 选中
    3.1行内选中
    选中到行末/行首:Shift+End/Home
    选中上一个/下一个单词:Ctrl+Shift+Left/Right
    3.2文件内选中
    选中闭合元素:Alt+Shift+Up
    恢复到上一个选中:Alt+Shift+Down
    选中下一个/上一个元素:Alt+Shift+Right/Left

     

    4 定位/选中/操作同时
    删除行:Ctrl+D
    删除下一个/上一个单词:Ctrl+Delete/Backspace
    删除到行末:Ctrl+Shift+Delete
    在当前行上插入一行:Ctrl+Shift+Enter
    在当前行下插入一行: Shift+Enter
    上下移动选中的行:Alt+Up/Down
    拷贝选中的行:Ctrl+Alt+Up/Down

     

    5其它的代码编辑类快捷键
    保存:Ctrl+S
    保存所有:Ctrl+Shift+S
    下一个命中的项(搜索之后):Ctrl+.
    注释:Ctrl+/
    添加导入:Ctrl+Shift+M
    显示快捷键帮助:Ctrl+Shift+L
    变为大/小写:Ctrl+Shift+X/Y

     

    6 重构
    显示重构菜单:Alt+Shift+T
    重构-改变方法签名:Alt+Shift+C
    重构-移动:Alt+Shift+V
    重构-重命名:Alt+Shift+R

     

    7 编辑器、视图、透视图切换
    下一个编辑器:Ctrl+F6
    下一个视图:Ctrl+F7
    下一个透视图:Ctrl+F8
    最大化当前视图或编辑器:Ctrl+M
    激活编辑器:F12

     

    8 Debug
    F5:Step Into(debug)
    F6:Step over(debug)
    F7:Step return(debug)
    F8:Resume(debug)
    F11:debug上一个应用(debug)

     

    9 Up/Down/Right/Left类快捷键
    Ctrl
    前一个/后一个单词:Ctrl+Right/Left
    上下滚屏:Ctrl+Up/Down
    Alt
    上一个/下一个光标的位置:Alt+Left/Right
    上下移动选中的行:Alt+Up/Down
    Shift
    选中上一个/下一个字符:Shift+Left/Right
    选中上一行/下一行(从当前光标位置开始):Shift+Up/Down
    Ctrl+Shift
    上一个/下一个成员(成员对象或成员函数):Ctrl+Shift+Up/Down
    选中上一个/下一个单词:Ctrl+Shift+Left/Right
    Alt+Shift
    选中闭合元素:Alt+Shift+Up
    恢复到上一个选中:Alt+Shift+Down
    选中下一个/上一个元素:Alt+Shift+Right/Left
    拷贝选中的行:Ctrl+Alt+Up/Down
    Ctrl+Alt
    拷贝选中的行:Ctrl+Alt+Up/Down

     

    10 F类快捷键
    F2:显示提示/重命名
    F3:打开选中元素的声明
    F4:打开选中元素的类型继承结构
    F5:刷新
    F5:Step Into(debug)
    F6:Step over(debug)
    F7:Step return(debug)
    F8:Resume(debug)
    F11:debug上一个应用(debug)
    F12:激活编辑器
    ================================================================
    ================================================================
    MyEclipse使用技巧和快捷键2008-01-23 09:22Eclipse本身很快的,但是加上了myeclipse后,就狂占内存,而且速度狂慢,那如何让Eclipse拖着myeclipse狂飚呢?这里提供一个技巧:取消自动validation
            validation有一堆,什么xml、jsp、jsf、js等等,我们没有必要全部都去自动校验一下,只是需要的时候才会手工校验一下,速度立马提升好几个档次!
    取消方法: windows-->perferences-->myeclipse-->validation
            除开Manual下面的复选框全部选中之外,其他全部不选
            手工验证方法:
            在要验证的文件上,单击鼠标右键-->myeclipse-->run validation

    程序代码自动排版:Ctrl+Shift+F,会自动把代码进行格式化的排版,非常方便
    快速执行程序:Ctrl + F11第一次执行时,它会询问您执行模式,设置好后,以后只要按这个热键,它就会快速执行。

    Ctrl+Shift+/ 加上段注释/**/

    Ctrl+Shift+\ 取消段注释/**/

    Ctrl+/ 加上行注释或取消行注释

    自动汇入所需要的类别:Ctrl+Shift+M Ctrl+Shift+O 好象使用Ctrl+Shift+O 也可以

    按new Remote Site,Name填 svn , URL填http://subclipse.tigris.org/update,一直next到finished为止

    MyEclipse 快捷键
    (1)Ctrl+M切换窗口的大小
    (2)Ctrl+Q跳到最后一次的编辑处
    (3)F2当鼠标放在一个标记处出现Tooltip时候按F2则把鼠标移开时Tooltip还会显示即Show Tooltip Description。
    F3跳到声明或定义的地方。
    F5单步调试进入函数内部。
    F6单步调试不进入函数内部,如果装了金山词霸2006则要把“取词开关”的快捷键改成其他的。
    F7由函数内部返回到调用处。
    F8一直执行到下一个断点。
    (4)Ctrl+Pg~对于XML文件是切换代码和图示窗口
    (5)Ctrl+Alt+I看Java文件中变量的相关信息
    (6)Ctrl+PgUp对于代码窗口是打开“Show List”下拉框,在此下拉框里显示有最近曾打开的文件
    (7)Ctrl+/ 在代码窗口中是这种//~注释。
    Ctrl+Shift+/ 在代码窗口中是这种/*~*/注释,在JSP文件窗口中是<!--~-->。
    (8)Alt+Shift+O(或点击工具栏中的Toggle Mark Occurrences按钮) 当点击某个标记时可使本页面中其他地方的此标记黄色凸显,并且窗口的右边框会出现白色的方块,点击此方块会跳到此标记处。
    (9)右击窗口的左边框即加断点的地方选Show Line Numbers可以加行号。
    (10)Ctrl+I格式化激活的元素Format Active Elements。
    Ctrl+Shift+F格式化文件Format Document。
    (11)Ctrl+S保存当前文件。
    Ctrl+Shift+S保存所有未保存的文件。
    (12)Ctrl+Shift+M(先把光标放在需导入包的类名上) 作用是加Import语句。
    Ctrl+Shift+O作用是缺少的Import语句被加入,多余的Import语句被删除。
    (13)Ctrl+Space提示键入内容即Content Assist,此时要将输入法中Chinese(Simplified)IME-Ime/Nonlme Toggle的快捷键(用于切换英文和其他文字)改成其他的。
    Ctrl+Shift+Space提示信息即Context Information。
    (14)双击窗口的左边框可以加断点。
    (15)Ctrl+D删除当前行

    posted @ 2008-12-10 14:30 jiafang83 阅读(4781) | 评论 (0)编辑 收藏
    转载:http://join-18.javaeye.com/blog/183051

    1.介绍
    1)DOM(JAXP Crimson解析器)
    DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准。DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作。由于它是基于信息层次的,因而DOM被认为是基于树或基于对象的。DOM以及广义的基于树的处理具有几个优点。首先,由于树在内存中是持久的,因此可以修改它以便应用程序能对数据和结构作出更改。它还可以在任何时候在树中上下导航,而不是像SAX那样是一次性的处理。DOM使用起来也要简单得多。
    2)SAX
    SAX处理的优点非常类似于流媒体的优点。分析能够立即开始,而不是等待所有的数据被处理。而且,由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优点。事实上,应用程序甚至不必解析整个文档;它可以在某个条件得到满足时停止解析。一般来说,SAX还比它的替代者DOM快许多。
    选择DOM还是选择SAX? 对于需要自己编写代码来处理XML文档的开发人员来说, 选择DOM还是SAX解析模型是一个非常重要的设计决策。 DOM采用建立树形结构的方式访问XML文档,而SAX采用的事件模型。
    DOM解析器把XML文档转化为一个包含其内容的树,并可以对树进行遍历。用DOM解析模型的优点是编程容易,开发人员只需要调用建树的指令,然后利用navigation APIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用DOM解析器的时候需要处理整个XML文档,所以对性能和内存的要求比较高,尤其是遇到很大的XML文件的时候。由于它的遍历能力,DOM解析器常用于XML文档需要频繁的改变的服务中。
    SAX解析器采用了基于事件的模型,它在解析XML文档的时候可以触发一系列的事件,当发现给定的tag的时候,它可以激活一个回调方法,告诉该方法制定的标签已经找到。SAX对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的tag.特别是当开发人员只需要处理文档中所包含的部分数据时,SAX这种扩展能力得到了更好的体现。但用SAX解析器的时候编码工作会比较困难,而且很难同时访问同一个文档中的多处不同数据。
    3)JDOM http://www.jdom.org
    JDOM的目的是成为Java特定文档模型,它简化与XML的交互并且比使用DOM实现更快。由于是第一个Java特定模型,JDOM一直得到大力推广和促进。正在考虑通过“Java规范请求JSR-102”将它最终用作“Java标准扩展”。从2000年初就已经开始了JDOM开发。
    JDOM与DOM主要有两方面不同。首先,JDOM仅使用具体类而不使用接口。这在某些方面简化了API,但是也限制了灵活性。第二,API大量使用了Collections类,简化了那些已经熟悉这些类的Java开发者的使用。
    JDOM文档声明其目的是“使用20%(或更少)的精力解决80%(或更多)Java/XML问题”(根据学习曲线假定为20%)。JDOM对于大多数Java/XML应用程序来说当然是有用的,并且大多数开发者发现API比DOM容易理解得多。JDOM还包括对程序行为的相当广泛检查以防止用户做任何在XML中无意义的事。然而,它仍需要您充分理解XML以便做一些超出基本的工作(或者甚至理解某些情况下的错误)。这也许是比学习DOM或JDOM接口都更有意义的工作。
    JDOM自身不包含解析器。它通常使用SAX2解析器来解析和验证输入XML文档(尽管它还可以将以前构造的DOM表示作为输入)。它包含一些转换器以将JDOM表示输出成SAX2事件流、DOM模型或XML文本文档。JDOM是在Apache许可证变体下发布的开放源码。
    4)DOM4J http://dom4j.sourceforge.net
    虽然DOM4J代表了完全独立的开发结果,但最初,它是JDOM的一种智能分支。它合并了许多超出基本XML文档表示的功能,包括集成的XPath支持、XML Schema支持以及用于大文档或流化文档的基于事件的处理。它还提供了构建文档表示的选项,它通过DOM4J API和标准DOM接口具有并行访问功能。从2000下半年开始,它就一直处于开发之中。
    为支持所有这些功能,DOM4J使用接口和抽象基本类方法。DOM4J大量使用了API中的Collections类,但是在许多情况下,它还提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是,虽然DOM4J付出了更复杂的API的代价,但是它提供了比JDOM大得多的灵活性。
    在添加灵活性、XPath集成和对大文档处理的目标时,DOM4J的目标与JDOM是一样的:针对Java开发者的易用性和直观操作。它还致力于成为比JDOM更完整的解决方案,实现在本质上处理所有Java/XML问题的目标。在完成该目标时,它比JDOM更少强调防止不正确的应用程序行为。
    DOM4J是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML,特别值得一提的是连Sun的JAXM也在用DOM4J.
    2、比较
    1)DOM4J性能最好,连Sun的JAXM也在用DOM4J.目前许多开源项目中大量采用DOM4J,例如大名鼎鼎的Hibernate也用DOM4J来读取XML配置文件。如果不考虑可移植性,那就采用DOM4J.
    2)JDOM和DOM在性能测试时表现不佳,在测试10M文档时内存溢出。在小文档情况下还值得考虑使用DOM和JDOM.虽然JDOM的开发者已经说明他们期望在正式发行版前专注性能问题,但是从性能观点来看,它确实没有值得推荐之处。另外,DOM仍是一个非常好的选择。DOM实现广泛应用于多种编程语言。它还是许多其它与XML相关的标准的基础,因为它正式获得W3C推荐(与基于非标准的Java模型相对),所以在某些类型的项目中可能也需要它(如在JavaScript中使用DOM)。
    3)SAX表现较好,这要依赖于它特定的解析方式-事件驱动。一个SAX检测即将到来的XML流,但并没有载入到内存(当然当XML流被读入时,会有部分文档暂时隐藏在内存中)。

    3.四种XML操作方式的基本使用方法
    xml文件:
    <?xml version="1.0" encoding="GB2312"?>
    <RESULT>
    <VALUE>
    <NO>A1234</NO>
    <ADDR>四川省XX县XX镇XX路X段XX号</ADDR>
    </VALUE>
    <VALUE>
    <NO>B1234</NO>
       <ADDR>四川省XX市XX乡XX村XX组</ADDR>
    </VALUE>
    </RESULT>
    1)DOM
    import java.io.*;
    import java.util.*;
    import org.w3c.dom.*;
    import javax.xml.parsers.*;
    public class MyXMLReader{
     public static void main(String arge[]){
    long lasting =System.currentTimeMillis();
    try{
     File f=new File("data_10k.xml");
     DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
     DocumentBuilder builder=factory.newDocumentBuilder();
     Document doc = builder.parse(f);
     NodeList nl = doc.getElementsByTagName("VALUE");
     for (int i=0;i<nl.getLength();i++){
    System.out.print("车牌号码:" +
    doc.getElementsByTagName("NO").item(i).getFirstChild().getNodeValue());
    System.out.println("车主地址:" +
    doc.getElementsByTagName("ADDR").item(i).getFirstChild().getNodeValue());
       }
    }catch(Exception e){
     e.printStackTrace();
    }
    2)SAX
    import org.xml.sax.*;
    import org.xml.sax.helpers.*;
    import javax.xml.parsers.*;
    public class MyXMLReader extends DefaultHandler {
     java.util.Stack tags = new java.util.Stack();
     public MyXMLReader() {
    super();
    }
     public static void main(String args[]) {
    long lasting = System.currentTimeMillis();
    try {
     SAXParserFactory sf = SAXParserFactory.newInstance();
     SAXParser sp = sf.newSAXParser();
     MyXMLReader reader = new MyXMLReader();
     sp.parse(new InputSource("data_10k.xml"), reader);
    } catch (Exception e) {
     e.printStackTrace();
    }
    System.out.println("运行时间:" + (System.currentTimeMillis() - lasting) + "毫秒");}
    public void characters(char ch[], int start, int length) throws SAXException {
    String tag = (String) tags.peek();
    if (tag.equals("NO")) {
     System.out.print("车牌号码:" + new String(ch, start, length));
    }
    if (tag.equals("ADDR")) {
    System.out.println("地址:" + new String(ch, start, length));
    }
    }
    public void startElement(String uri,String localName,String qName,Attributes attrs) {
    tags.push(qName);}
    }
    3)JDOM
    import java.io.*;
    import java.util.*;
    import org.jdom.*;
    import org.jdom.input.*;
    public class MyXMLReader {
     public static void main(String arge[]) {
    long lasting = System.currentTimeMillis();
    try {
     SAXBuilder builder = new SAXBuilder();
     Document doc = builder.build(new File("data_10k.xml"));
     Element foo = doc.getRootElement();
     List allChildren = foo.getChildren();
     for(int i=0;i<allChildren.size();i++) {
    System.out.print("车牌号码:" +
    ((Element)allChildren.get(i)).getChild("NO").getText());
    System.out.println("车主地址:" +
    ((Element)allChildren.get(i)).getChild("ADDR").getText());
     }
    } catch (Exception e) {
     e.printStackTrace();
    }
    }
    4)DOM4J
    import java.io.*;
    import java.util.*;
    import org.dom4j.*;
    import org.dom4j.io.*;
    public class MyXMLReader {
     public static void main(String arge[]) {
    long lasting = System.currentTimeMillis();
    try {
     File f = new File("data_10k.xml");
     SAXReader reader = new SAXReader();
     Document doc = reader.read(f);
     Element root = doc.getRootElement();
     Element foo;
     for (Iterator i = root.elementIterator("VALUE"); i.hasNext() {
    foo = (Element) i.next();
    System.out.print("车牌号码:" + foo.elementText("NO"));
    System.out.println("车主地址:" + foo.elementText("ADDR"));
     }
    } catch (Exception e) {
     e.printStackTrace();
    }
    )
    posted @ 2008-12-10 09:38 jiafang83 阅读(182) | 评论 (0)编辑 收藏
        类Object是类层次结构的根类,每一个类都使用Object作为超类,所有对象(包括数组)都实现这个类的方法。jdk1.5中,描述了该类中的11个方法

    1.getClass

    public final Class<? extends Object> getClass()
    返回一个对象的运行时类。该 Class 对象是由所表示类的 static synchronized 方法锁定的对象。

     

    返回:
    表示该对象的运行时类的 java.lang.Class 对象。此结果属于类型 Class<? extends X>,其中 X 表示清除表达式中的静态类型,该表达式调用 getClass

    2.hashCode

    public int hashCode()
    返回该对象的哈希码值。支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表。

    hashCode 的常规协定是:

    • 在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
    • 如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
    • 以下情况 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。

    实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)

     

    返回:
    此对象的一个哈希码值。

    3.equals

    public boolean equals(Object obj)
    指示某个其他对象是否与此对象“相等”。

    equals 方法在非空对象引用上实现相等关系:

    • 自反性:对于任何非空引用值 xx.equals(x) 都应返回 true
    • 对称性:对于任何非空引用值 xy,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true
    • 传递性:对于任何非空引用值 xyz,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true
    • 一致性:对于任何非空引用值 xy,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
    • 对于任何非空引用值 xx.equals(null) 都应返回 false

    Object 类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 xy,当且仅当 xy 引用同一个对象时,此方法才返回 truex == y 具有值 true)。

    注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。

     

    参数:
    obj - 要与之比较的引用对象。
    返回:
    如果此对象与 obj 参数相同,则返回 true;否则返回 false

    4.clone

    protected Object clone()
    throws CloneNotSupportedException
    创建并返回此对象的一个副本。“副本”的准确含义可能依赖于对象的类。一般来说,对于任何对象 x,如果表达式:
    x.clone() != x
    是正确的,则表达式:
    x.clone().getClass() == x.getClass()
    将为 true,但这些不是绝对条件。一般情况下是:
    x.clone().equals(x)
    将为 true,但这不是绝对条件。

    按照惯例,返回的对象应该通过调用 super.clone 获得。如果一个类及其所有的超类(Object 除外)都遵守此约定,则 x.clone().getClass() == x.getClass()

    按照惯例,此方法返回的对象应该独立于该对象(正被克隆的对象)。要获得此独立性,在 super.clone 返回对象之前,有必要对该对象的一个或多个字段进行修改。这通常意味着要复制包含正在被克隆对象的内部“深层结构”的所有可变对象,并使用对副本的引用替换对这些对象的引用。如果一个类只包含基本字段或对不变对象的引用,那么通常不需要修改 super.clone 返回的对象中的字段。

    Object 类的 clone 方法执行特定的克隆操作。首先,如果此对象的类不能实现接口 Cloneable,则会抛出 CloneNotSupportedException。注意:所有的数组都被视为实现接口 Cloneable。否则,此方法会创建此对象的类的一个新实例,并像通过分配那样,严格使用此对象相应字段的内容初始化该对象的所有字段;这些字段的内容没有被自我克隆。所以,此方法执行的是该对象的“浅表复制”,而不“深层复制”操作。

    Object 类本身不实现接口 Cloneable,所以在类为 Object 的对象上调用 clone 方法将会导致在运行时抛出异常。

     

    返回:
    此实例的一个克隆。
    抛出:
    CloneNotSupportedException - 如果对象的类不支持 Cloneable 接口,则重写 clone 方法的子类也会抛出此异常,以指示无法克隆某个实例。

    5.toString

    public String toString()
    返回该对象的字符串表示。通常,toString 方法会返回一个“以文本方式表示”此对象的字符串。结果应是一个简明但易于读懂。建议所有子类都重写此方法。

    Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串,它的值等于:

    getClass().getName() + '@' + Integer.toHexString(hashCode())
    

     

    返回:
    该对象的字符串表示形式。

    6.notify

    public final void notify()
    唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。

    直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。

    此方法只应由作为此对象监视器的所有者的线程来调用。通过以下三种方法之一,线程可以成为此对象监视器的所有者:

    • 通过执行此对象的同步 (Sychronized) 实例方法。
    • 通过执行在此对象上进行同步的 synchronized 语句的正文。
    • 对于 Class 类型的对象,可以通过执行该类的同步静态方法。

    一次只能有一个线程拥有对象的监视器。

     

    抛出:
    IllegalMonitorStateException - 如果当前的线程不是此对象监视器的所有者。

    7.notifyAll

    public final void notifyAll()
    唤醒在此对象监视器上等待的所有线程。线程通过调用其中一个 wait 方法,在对象的监视器上等待。

    直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。

    此方法只应由作为此对象监视器的所有者的线程来调用。请参阅 notify 方法,了解线程能够成为监视器所有者的方法的描述。

     

    抛出:
    IllegalMonitorStateException - 如果当前的线程不是此对象监视器的所有者。

    8.finalize

    protected void finalize()
    throws Throwable
    当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。子类重写 finalize 方法,以配置系统资源或执行其他清除。

    finalize 的常规协定是:当 JavaTM 虚拟机已确定尚未终止的任何线程无法再通过任何方法访问此对象时,将调用此方法,除非由于准备终止的其他某个对象或类的终结操作执行了某个操作。finalize 方法可以采取任何操作,其中包括再次使此对象对其他线程可用;不过,finalize 的主要目的是在不可撤消地丢弃对象之前执行清除操作。例如,表示输入/输出连接的对象的 finalize 方法可执行显式 I/O 事务,以便在永久丢弃对象之前中断连接。

    Object 类的 finalize 方法执行非特殊性操作;它仅执行一些常规返回。Object 的子类可以重写此定义。

    Java 编程语言不保证哪个线程将调用某个给定对象的 finalize 方法。但可以保证在调用 finalize 时,调用 finalize 的线程将不会持有任何用户可见的同步锁定。如果 finalize 方法抛出未捕获的异常,那么该异常将被忽略,并且该对象的终结操作将终止。

    在启用某个对象的 finalize 方法后,将不会执行进一步操作,直到 Java 虚拟机再次确定尚未终止的任何线程无法再通过任何方法访问此对象,其中包括由准备终止的其他对象或类执行的可能操作,在执行该操作时,对象可能被丢弃。

    对于任何给定对象,Java 虚拟机最多只调用一次 finalize 方法。

    finalize 方法抛出的任何异常都会导致此对象的终结操作停止,但可以通过其他方法忽略它。

     

    抛出:
    Throwable - 此方法抛出的 Exception

    9.wait

    public final void wait(long timeout)
    throws InterruptedException
    导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。

    当前的线程必须拥有此对象监视器。

    此方法导致当前线程(称之为 T)将其自身放置在对象的等待集中,然后放弃此对象上的所有同步要求。出于线程调度目的,线程 T 被禁用,且处于休眠状态,直到发生以下四种情况之一:

    • 其他某个线程调用此对象的 notify 方法,并且线程 T 碰巧被任选为被唤醒的线程。
    • 其他某个线程调用此对象的 notifyAll 方法。
    • 其他某个线程中断线程 T
    • 已经到达指定的实际时间。但是,如果 timeout 为零,则不考虑实际时间,该线程将一直等待,直到获得通知。
    然后,从对象的等待集中删除线程 T,并重新进行线程调度。然后,该线程以常规方式与其他线程竞争,以获得在该对象上同步的权利;一旦获得对该对象的控制权,该对象上的所有其同步声明都将被还原到以前的状态 - 这就是调用 wait 方法时的情况。然后,线程 Twait 方法的调用中返回。所以,从 wait 方法返回时,该对象和线程 T 的同步状态与调用 wait 方法时的情况完全相同。

    在没有被通知、中断或超时的情况下,线程还可以唤醒一个所谓的虚假唤醒 (spurious wakeup)。虽然这种情况在实践中很少发生,但是应用程序必须通过以下方式防止其发生,即对应该导致该线程被提醒的条件进行测试,如果不满足该条件,则继续等待。换句话说,等待应总是发生在循环中,如下面的示例:

    synchronized (obj) {
    while (<condition does not hold>)
    obj.wait(timeout);
    ... // Perform action appropriate to condition
    }
    
    (有关这一主题的更多信息,请参阅 Doug Lea 撰写的《Concurrent Programming in Java (Second Edition)》(Addison-Wesley, 2000) 中的第 3.2.3 节或 Joshua Bloch 撰写的《Effective Java Programming Language Guide》(Addison-Wesley, 2001) 中的第 50 项。

    如果当前线程在等待时被其他线程中断,则会抛出 InterruptedException。在按上述形式恢复此对象的锁定状态时才会抛出此异常。

    注意,由于 wait 方法将当前的线程放入了对象的等待集中,所以它只能解除此对象的锁定;可以同步当前线程的任何其他对象在线程等待时仍处于锁定状态。

    此方法只应由作为此对象监视器的所有者的线程来调用。请参阅 notify 方法,了解线程能够成为监视器所有者的方法的描述。

     

    参数:
    timeout - 要等待的最长时间(以毫秒为单位)。
    抛出:
    IllegalArgumentException - 如果超时值为负。
    IllegalMonitorStateException - 如果当前的线程不是此对象监视器的所有者。
    InterruptedException - 如果在当前线程等待通知之前或者正在等待通知时,另一个线程中断了当前线程。在抛出此异常时,当前线程的中断状态 被清除。

    10.wait

    public final void wait(long timeout,
    int nanos)
    throws InterruptedException
    导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。

    此方法类似于一个参数的 wait 方法,但它允许更好地控制在放弃之前等待通知的时间量。用毫微秒度量的实际时间量可以通过以下公式计算出来:

    1000000*timeout+nanos

    在其他所有方面,此方法执行的操作与带有一个参数的 wait(long) 方法相同。需要特别指出的是,wait(0, 0)wait(0) 相同。

    当前的线程必须拥有此对象监视器。该线程发布对此监视器的所有权,并等待下面两个条件之一发生:

    • 其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。
    • timeout 毫秒值与 nanos 毫微秒参数值之和指定的超时时间已用完。

    然后,该线程等到重新获得对监视器的所有权后才能继续执行。

    对于某一个参数的版本,实现中断和虚假唤醒是有可能的,并且此方法应始终在循环中使用:

    synchronized (obj) {
    while (<condition does not hold>)
    obj.wait(timeout, nanos);
    ... // Perform action appropriate to condition
    }
    
    此方法只应由作为此对象监视器的所有者的线程来调用。请参阅 notify 方法,了解线程能够成为监视器所有者的方法的描述。

     

    参数:
    timeout - 要等待的最长时间(以毫秒为单位)。
    nanos - 额外时间(以毫微秒为单位,范围是 0-999999)。
    抛出:
    IllegalArgumentException - 如果超时值是负数,或者毫微秒值不在 0-999999 范围内。
    IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。
    InterruptedException - 如果在当前线程等待通知之前或者正在等待通知时,其他线程中断了当前线程。在抛出此异常时,当前线程的中断状态 被清除。

    11.wait

    public final void wait()
    throws InterruptedException
    导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。换句话说,此方法的行为就好像它仅执行 wait(0) 调用一样。

    当前的线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。

    对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用:

    synchronized (obj) {
    while (<condition does not hold>)
    obj.wait();
    ... // Perform action appropriate to condition
    }
    
    此方法只应由作为此对象监视器的所有者的线程来调用。请参阅 notify 方法,了解线程能够成为监视器所有者的方法的描述。

     

    抛出:
    IllegalMonitorStateException - 如果当前的线程不是此对象监视器的所有者。
    InterruptedException - 如果在当前线程等待通知之前或者正在等待通知时,另一个线程中断了当前线程。在抛出此异常时,当前线程的中断状态 被清除。
    posted @ 2008-12-05 10:25 jiafang83 阅读(8159) | 评论 (0)编辑 收藏

        今天忽然想起这么个问题:在eclipse下运行的java程序,它们的字节码文件跑哪去啦,怎么在项目中看不到呢?在网上查了一下,终于找到了原因所在。
        原来classes文件夹所在的目录是程序编译输出的路径,只有在eclipse下的Resource透视图下,才能显示出来,在其它透视图下都不能显示。

                     
    posted @ 2008-12-05 10:02 jiafang83 阅读(3358) | 评论 (0)编辑 收藏
         摘要: 转载:http://download.csdn.net/source/245338   1. Jdbc的六个编程步骤 1. 注册一个驱动 注册驱动程序有三种方式:                &nbs...  阅读全文
    posted @ 2008-12-01 17:00 jiafang83 阅读(1031) | 评论 (0)编辑 收藏
         摘要:   转载:http://www.builder.com.cn/2007/1211/678982.shtml 目前,国内外信息化建设已经进入基于Web应用为核心的阶段, Java作为应用于网络的最好语言,前景无限看好。然而,就算用Java建造一个不是很烦琐的web应用,也不是件轻松的事情。概括一下,实施Java的WEB项目需要掌握的技术如下: l  &...  阅读全文
    posted @ 2008-12-01 16:23 jiafang83 阅读(192) | 评论 (0)编辑 收藏
         摘要: 转载:http://www.blogjava.net/rongxh7      分页显示一直是web开发中一大烦琐的难题,传统的网页设计只在一个JSP或者ASP页面中书写所有关于数据库操作的代码,那样做分页可能简单一点,但当把网站分层开发后,分页就比较困难了,下面是我做Spring+Hibernate+Struts2项目时设计的分页代码,与大家分享交流。 ...  阅读全文
    posted @ 2008-12-01 14:08 jiafang83 阅读(1406) | 评论 (2)编辑 收藏
    转载:http://peak.javaeye.com/blog/52606

    1、 PermGen space的全称是Permanent Generation space,是指内存的永久保存区域OutOfMemoryError: PermGen space从表面上看就是内存益出,解决方法也一定是加大内存。说说为什么会内存益出:这一部分用于存放Class和Meta的信息,Class在被 Load的时候被放入PermGen space区域,它和和存放Instance的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的APP会LOAD很多CLASS的话,就很可能出现PermGen space错误。这种错误常见在web服务器对JSP进行pre compile的时候。

    改正方法:-Xms256m -Xmx256m -XX:MaxNewSize=256m -XX:MaxPermSize=256m
    2、

    在tomcat中redeploy时出现outofmemory的错误.

    可以有以下几个方面的原因:

    1,使用了proxool,因为proxool内部包含了一个老版本的cglib.

    2, log4j,最好不用,只用common-logging

    3, 老版本的cglib,快点更新到最新版。

    4,更新到最新的hibernate3.2


    3、

    这里以tomcat环境为例,其它WEB服务器如jboss,weblogic等是同一个道理。
    一、java.lang.OutOfMemoryError: PermGen space
    PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,
    这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中,
    它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对
    PermGen space进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGen space错误,
    这种错误常见在web服务器对JSP进行pre compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小
    超过了jvm默认的大小(4M)那么就会产生此错误信息了。
    解决方法: 手动设置MaxPermSize大小

    修改TOMCAT_HOME/bin/catalina.sh
    在“echo "Using CATALINA_BASE:   $CATALINA_BASE"”上面加入以下行:
    JAVA_OPTS="-server -XX:PermSize=64M -XX:MaxPermSize=128m
    建议:将相同的第三方jar文件移置到tomcat/shared/lib目录下,这样可以达到减少jar 文档重复占用内存的目的。

    二、java.lang.OutOfMemoryError: Java heap space
    Heap size 设置
    JVM堆的设置是指java程序运行过程中JVM可以调配使用的内存空间的设置.JVM在启动的时候会自动设置Heap size的值,
    其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等选项可
    进行设置。Heap size 的大小是Young Generation 和Tenured Generaion 之和。
    提示:在JVM中如果98%的时间是用于GC且可用的Heap size 不足2%的时候将抛出此异常信息。
    提示:Heap Size 最大不要超过可用物理内存的80%,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。
    解决方法:手动设置Heap size
    修改TOMCAT_HOME/bin/catalina.sh
    在“echo "Using CATALINA_BASE:   $CATALINA_BASE"”上面加入以下行:
    JAVA_OPTS="-server -Xms800m -Xmx800m   -XX:MaxNewSize=256m"

    三、实例,以下给出1G内存环境下java jvm 的参数设置参考:

    JAVA_OPTS="-server -Xms800m -Xmx800m  -XX:PermSize=64M -XX:MaxNewSize=256m -XX:MaxPermSize=128m -Djava.awt.headless=true "


    三、相关资料

    http://www.tot.name/show/3/7/20061112220131.htm

    http://www.tot.name/show/3/7/20061112220054.htm

    http://www.tot.name/show/3/7/20061112220201.htm

    题外话:经常看到网友抱怨tomcat的性能不如...,不稳定等,其实根据笔者几年的经验,从"互联星空“到现在的房产门户网,我们
    均使用tomcat作为WEB服务器,每天访问量百万多,tomcat仍然运行良好。建议大家有问题多从自己程序入手,多看看java的DOC文档
    并详细了解JVM的知识。这样开发的程序才会健壮。

    JVM 性能调整的一些基本概念
    http://www.wujianrong.com/archives/2007/02/jvm_1.html#more
    apache+Tomcat负载平衡设置详解

    http://www.wujianrong.com/archives/2006/11/apachetomcat.html
    java - the Java application launcher

    http://java.sun.com/j2se/1.3/docs/tooldocs/linux/java.html
    posted @ 2008-11-21 17:16 jiafang83 阅读(158) | 评论 (0)编辑 收藏

     
    转自:http://www.java-cn.com/technology/tech/4310.html

    本文阐述了怎么使用DBMS存储过程。我阐述了使用存储过程的基本的和高级特性,比如返回ResultSet。本文假设你对DBMS和JDBC已经非常熟悉,也假设你能够毫无障碍地阅读其它语言写成的代码(即不是Java的语言),但是,并不要求你有任何存储过程的编程经历。

    存储过程是指保存在数据库并在数据库端执行的程序。你可以使用特殊的语法在Java类中调用存储过程。在调用时,存储过程的名称及指定的参数通过JDBC连接发送给DBMS,执行存储过程并通过连接(如果有)返回结果。
    使用存储过程拥有和使用基于EJB或CORBA这样的应用服务器一样的好处。区别是存储过程可以从很多流行的DBMS中免费使用,而应用服务器大都非常昂贵。这并不只是许可证费用的问题。使用应用服务器所需要花费的管理、编写代码的费用,以及客户程序所增加的复杂性,都可以通过DBMS中的存储过程所整个地替代。

    你可以使用Java,Python,Perl或C编写存储过程,但是通常使用你的DBMS所指定的特定语言。Oracle使用PL/SQL,PostgreSQL使用pl/pgsql,DB2使用Procedural SQL。这些语言都非常相似。在它们之间移植存储过程并不比在Sun的EJB规范不同实现版本之间移植Session Bean困难。并且,存储过程是为嵌入SQL所设计,这使得它们比Java或C等语言更加友好地方式表达数据库的机制。

    因为存储过程运行在DBMS自身,这可以帮助减少应用程序中的等待时间。不是在Java代码中执行4个或5个SQL语句,而只需要在服务器端执行1个存储过程。网络上的数据往返次数的减少可以戏剧性地优化性能。

    使用存储过程

    简单的老的JDBC通过CallableStatement类支持存储过程的调用。该类实际上是PreparedStatement的一个子类。假设我们有一个poets数据库。数据库中有一个设置诗人逝世年龄的存储过程。下面是对老酒鬼Dylan Thomas(old soak Dylan Thomas,不指定是否有关典故、文化,请批评指正。译注)进行调用的详细代码:


    try{ 
    int age = 39;

    String poetName = "dylan thomas";

    CallableStatement proc = connection.prepareCall("{ call set_death_age(?, ?) }");

    proc.setString(1, poetName);

    proc.setInt(2, age);

    cs.execute();

    }catch (SQLException e){ // ....}



    传给prepareCall方法的字串是存储过程调用的书写规范。它指定了存储过程的名称,?代表了你需要指定的参数。
    和JDBC集成是存储过程的一个很大的便利:为了从应用中调用存储过程,不需要存根(stub)类或者配置文件,除了你的DBMS的JDBC驱动程序外什么也不需要。

    当这段代码执行时,数据库的存储过程就被调用。我们没有去获取结果,因为该存储过程并不返回结果。执行成功或失败将通过例外得知。失败可能意味着调用存储过程时的失败(比如提供的一个参数的类型不正确),或者一个应用程序的失败(比如抛出一个例外指示在poets数据库中并不存在“Dylan Thomas”)

    结合SQL操作与存储过程

    映射Java对象到SQL表中的行相当简单,但是通常需要执行几个SQL语句;可能是一个SELECT查找ID,然后一个INSERT插入指定ID的数据。在高度规格化(符合更高的范式,译注)的数据库模式中,可能需要多个表的更新,因此需要更多的语句。Java代码会很快地膨胀,每一个语句的网络开销也迅速增加。
    将这些SQL语句转移到一个存储过程中将大大简化代码,仅涉及一次网络调用。所有关联的SQL操作都可以在数据库内部发生。并且,存储过程语言,例如PL/SQL,允许使用SQL语法,这比Java代码更加自然。下面是我们早期的存储过程,使用Oracle的PL/SQL语言编写:


    create procedure set_death_age(poet VARCHAR2, poet_age NUMBER) 

    poet_id NUMBER;

    begin SELECT id INTO poet_id FROM poets WHERE name = poet;

    INSERT INTO deaths (mort_id, age) VALUES (poet_id, poet_age);

    end set_death_age;



    很独特?不。我打赌你一定期待看到一个poets表上的UPDATE。这也暗示了使用存储过程实现是多么容易的一件事情。set_death_age几乎可以肯定是一个很烂的实现。我们应该在poets表中添加一列来存储逝世年龄。Java代码中并不关心数据库模式是怎么实现的,因为它仅调用存储过程。我们以后可以改变数据库模式以提高性能,但是我们不必修改我们代码。

    下面是调用上面存储过程的Java代码:


    public static void setDeathAge(Poet dyingBard, int age) throws SQLException{ 

    Connection con = null;

    CallableStatement proc = null;

    try {

    con = connectionPool.getConnection();

    proc = con.prepareCall("{ call set_death_age(?, ?) }");

    proc.setString(1, dyingBard.getName());

    proc.setInt(2, age);

    proc.execute();

    }

    finally {

    try { proc.close(); }

    catch (SQLException e) {}

    con.close();

    }

    }



    为了确保可维护性,建议使?孟裾舛?庋??tatic方法。这也使得调用存储过程的代码集中在一个简单的模版代码中。如果你用到许多存储过程,就会发现仅需要拷贝、粘贴就可以创建新的方法。因为代码的模版化,甚至也可以通过脚本自动生产调用存储过程的代码。

    Functions

    存储过程可以有返回值,所以CallableStatement类有类似getResultSet这样的方法来获取返回值。当存储过程返回一个值时,你必须使用registerOutParameter方法告诉JDBC驱动器该值的SQL类型是什么。你也必须调整存储过程调用来指示该过程返回一个值。

    下面接着上面的例子。这次我们查询Dylan Thomas逝世时的年龄。这次的存储过程使用PostgreSQL的pl/pgsql:


    create function snuffed_it_when (VARCHAR) returns integer 'declare 

    poet_id NUMBER;

    poet_age NUMBER;

    begin

    --first get the id associated with the poet.

    SELECT id INTO poet_id FROM poets WHERE name = $1;

    --get and return the age.

    SELECT age INTO poet_age FROM deaths WHERE mort_id = poet_id;

    return age;

    end;' language 'pl/pgsql';



    另外,注意pl/pgsql参数名通过Unix和DOS脚本的$n语法引用。同时,也注意嵌入的注释,这是和Java代码相比的另一个优越性。在Java中写这样的注释当然是可以的,但是看起来很凌乱,并且和SQL语句脱节,必须嵌入到Java String中。

    下面是调用这个存储过程的Java代码:


    connection.setAutoCommit(false); 

    CallableStatement proc = connection.prepareCall("{ ? = call snuffed_it_when(?) }");

    proc.registerOutParameter(1, Types.INTEGER);

    proc.setString(2, poetName);

    cs.execute();

    int age = proc.getInt(2);



    如果指定了错误的返回值类型会怎样?那么,当调用存储过程时将抛出一个RuntimeException,正如你在ResultSet操作中使用了一个错误的类型所碰到的一样。

    复杂的返回值

    关于存储过程的知识,很多人好像就熟悉我们所讨论的这些。如果这是存储过程的全部功能,那么存储过程就不是其它远程执行机制的替换方案了。存储过程的功能比这强大得多。
    当你执行一个SQL查询时,DBMS创建一个叫做cursor(游标)的数据库对象,用于在返回结果中迭代每一行。ResultSet是当前时间点的游标的一个表示。这就是为什么没有缓存或者特定数据库的支持,你只能在ResultSet中向前移动。

    某些DBMS允许从存储过程中返回游标的一个引用。JDBC并不支持这个功能,但是Oracle、PostgreSQL和DB2的JDBC驱动器都支持在ResultSet上打开到游标的指针(pointer)。

    设想列出所有没有活到退休年龄的诗人,下面是完成这个功能的存储过程,返回一个打开的游标,同样也使用PostgreSQL的pl/pgsql语言:


    create procedure list_early_deaths () return refcursor as 'declare 

    toesup refcursor;

    begin

    open toesup for SELECT poets.name, deaths.age FROM poets, deaths
    -- all entries in deaths are for poets. -- but the table might become generic. 

    WHERE poets.id = deaths.mort_id AND deaths.age < 60;

    return toesup;

    end;' language 'plpgsql';



    下面是调用该存储过程的Java方法,将结果输出到PrintWriter:


    PrintWriter: 

    static void sendEarlyDeaths(PrintWriter out){

    Connection con = null;

    CallableStatement toesUp = null;

    try {

    con = ConnectionPool.getConnection();

    // PostgreSQL needs a transaction to do this... con.

    setAutoCommit(false); // Setup the call.

    CallableStatement toesUp = connection.prepareCall("{ ? = call list_early_deaths () }");

    toesUp.registerOutParameter(1, Types.OTHER);

    toesUp.execute();

    ResultSet rs = (ResultSet) toesUp.getObject(1);

    while (rs.next()) {

    String name = rs.getString(1);

    int age = rs.getInt(2);

    out.println(name + " was " + age + " years old.");

    }

    rs.close();

    }

    catch (SQLException e) { // We should protect these calls. toesUp.close(); con.close();

    }

    }



    因为JDBC并不直接支持从存储过程中返回游标,我们使用Types.OTHER来指示存储过程的返回类型,然后调用getObject()方法并对返回值进行强制类型转换。

    这个调用存储过程的Java方法是mapping的一个好例子。Mapping是对一个集上的操作进行抽象的方法。不是在这个过程上返回一个集,我们可以把操作传送进去执行。本例中,操作就是把ResultSet打印到一个输出流。这是一个值得举例的很常用的例子,下面是调用同一个存储过程的另外一个方法实现:


    public class ProcessPoetDeaths{ 

    public abstract void sendDeath(String name, int age);

    }

    static void mapEarlyDeaths(ProcessPoetDeaths mapper){

    Connection con = null;

    CallableStatement toesUp = null;

    try {

    con = ConnectionPool.getConnection();

    con.setAutoCommit(false);

    CallableStatement toesUp = connection.prepareCall("{ ? = call list_early_deaths () }");

    toesUp.registerOutParameter(1, Types.OTHER);

    toesUp.execute();

    ResultSet rs = (ResultSet) toesUp.getObject(1);

    while (rs.next()) {

    String name = rs.getString(1);

    int age = rs.getInt(2);

    mapper.sendDeath(name, age);

    }

    rs.close();

    } catch (SQLException e) { // We should protect these calls. toesUp.close();

    con.close();

    }

    }



    这允许在ResultSet数据上执行任意的处理,而不需要改变或者复制获取ResultSet的方法:


    static void sendEarlyDeaths(final PrintWriter out){ 

    ProcessPoetDeaths myMapper = new ProcessPoetDeaths() {

    public void sendDeath(String name, int age) {

    out.println(name + " was " + age + " years old.");

    }

    };

    mapEarlyDeaths(myMapper);

    }



    这个方法使用ProcessPoetDeaths的一个匿名实例调用mapEarlyDeaths。该实例拥有sendDeath方法的一个实现,和我们上面的例子一样的方式把结果写入到输出流。当然,这个技巧并不是存储过程特有的,但是和存储过程中返回的ResultSet结合使用,是一个非常强大的工具。

    结论

    存储过程可以帮助你在代码中分离逻辑,这基本上总是有益的。这个分离的好处有:
    ?6?1 快速创建应用,使用和应用一起改变和改善的数据库模式。
    ?6?1 数据库模式可以在以后改变而不影响Java对象,当我们完成应用后,可以重新设计更好的模式。
    ?6?1 存储过程通过更好的SQL嵌入使得复杂的SQL更容易理解。
    ?6?1 编写存储过程比在Java中编写嵌入的SQL拥有更好的工具--大部分编辑器都提供语法高亮!
    ?6?1 存储过程可以在任何SQL命令行中测试,这使得调试更加容易。

    并不是所有的数据库都支持存储过程,但是存在许多很棒的实现,包括免费/开源的和非免费的,所以移植并不是一个问题。Oracle、PostgreSQL和DB2都有类似的存储过程语言,并且有在线的社区很好地支持。
    存储过程工具很多,有像TOAD或TORA这样的编辑器、调试器和IDE,提供了编写、维护PL/SQL或pl/pgsql的强大的环境。

    存储过程确实增加了你的代码的开销,但是它们和大多数的应用服务器相比,开销小得多。

    posted @ 2008-11-20 15:25 jiafang83 阅读(181) | 评论 (0)编辑 收藏
    首先建立两个存储过程:
    存储过程p_1----从cell表中取出数据
    create proc p_1
    as
    select * from cell
    go
    存储过程p_2----往cell表里插入数据
    create proc p_2
        @name varchar(40),
        @remark varchar(40)
    as
    insert into cell(name,remark) values(@name,@remark)
    go
    调用存储过程p_1:
    import java.sql.*;

    /**
     * jdbc中调用存储过程
     * @author jiafang83
     *
     */
    public class Procedure2 {

        public static void main(String[] args) throws Exception {
            // TODO Auto-generated method stub
            String url = "jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=fish";
            String user = "bm";
            String pwd = "bm";
            Connection conn = null;
            CallableStatement proc = null;//执行sql存储过程的接口
            ResultSet rs = null;

    //        调用存储过程p_1:从Cell表中取出数据
            try{
                Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
                conn = DriverManager.getConnection(url,user,pwd);
                proc = conn.prepareCall("{? = call p_1 ()}");
                proc.registerOutParameter(1, Types.REAL);
                rs = proc.executeQuery();//取得结果集
                while(rs.next()){
                    System.out.println(rs.getString("name"));
                }
            }catch(Exception e){
                e.printStackTrace();
            }finally{
                if(rs!=null) rs.close();
                if(proc!=null)proc.close();
                if(conn!=null)conn.close();
            }
        }

    }

    调用存储过程p_2:
    import java.sql.*;

    /**
     * jdbc中调用存储过程
     * @author jiafang83
     *
     */
    public class Procedure {

        public static void main(String[] args) throws Exception {
            // TODO Auto-generated method stub
            String url = "jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=fish";
            String user = "bm";
            String pwd = "bm";
            Connection conn = null;
            CallableStatement proc = null;//执行sql存储过程的接口
           
    //        调用存储过程p_2:向Cell表中插入数据
            try{
                Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
                conn = DriverManager.getConnection(url,user,pwd);
                proc = conn.prepareCall("{call p_2 (?,?)}");
                proc.setString(1, "测试");
                proc.setString(2, "测试");
                proc.execute();
                System.out.println("成功调用存储过程,插入数据!");
            }catch(Exception e){
                e.printStackTrace();
            }finally{
                if(proc!=null)proc.close();
                if(conn!=null)conn.close();
            }
        }



    posted @ 2008-11-20 14:25 jiafang83 阅读(3016) | 评论 (0)编辑 收藏
        转载自:http://www.htmer.com/article/329.htm

        我们在装完SQL Server 2000数据库后,用企业管理器打开数据库,会发现里面默认安装了master、model、msdb、Northwind、pubs、tempdb这6个数据库,这些数据库是干什么的呢?下面就一一介绍之。

        1、master数据库
        master 数据库记录SQL Server系统的所有系统级别信息。它记录所有的登录帐户和系统配置设置。它还记录所有其它的数据库,其中包括数据库文件的位置。master数据库记录SQL Server的初始化信息,它始终有一个可用的最新master数据库备份。
       
        2、model数据库
        model 数据库用作在系统上创建的所有数据库的模板。当发出Create DATABASE语句时,新数据库的第一部分通过复制model数据库中的内容创建,剩余部分由空页填充。由于SQL Server每次启动时都要创建tempdb数据库,model数据库必须一直存在于SQL Server系统中。
       
        3、msdb数据库
        msdb数据库供SQL Server代理程序调度警报和作业以及记录操作员时使用。

        4、Northwind数据库
        Northwind数据库包含一个名为Northwind Traders的虚构公司的销售数据,该公司从事世界各地的特产食品进出口贸易。

        5、pubs数据库
        pubs数据库以一个图书出版公司为模型,用于演示SQL Server数据库中可用的许多选项。该数据库及其中的表经常在文档内容所介绍的示例中使用。

        6、tempdb数据库
        tempdb 数据库保存所有的临时表和临时存储过程。它还满足任何其它的临时存储要求,例如存储SQL Server生成的工作表。tempdb数据库是全局资源,所有连接到系统的用户的临时表和存储过程都存储在该数据库中。tempdb数据库在SQL Server每次启动时都重新创建,因此该数据库在系统启动时总是干净的。临时表和存储过程在连接断开时自动除去,而且当系统关闭后将没有任何连接处于活 动状态,因此tempdb数据库中没有任何内容会从SQL Server的一个会话保存到另一个会话。  
        默认情况下,在SQL Server在运行时tempdb数据库会根据需要自动增长。不过,与其它数据库不同,每次启动数据库引擎时,它会重置为其初始大小。如果为tempdb 数据库定义的大小较小,则每次重新启动SQL Server时,将tempdb数据库的大小自动增加到支持工作负荷所需的大小这一工作可能会成为系统处理负荷的一部分。为避免这种开销,可以使用 Alter DATABASE增加tempdb数据库的大小。

    posted @ 2008-11-19 14:06 jiafang83 阅读(528) | 评论 (0)编辑 收藏

    转自:http://c21.cnblogs.com/archive/2006/05/08/393779.html

    CREATE PROCEDURE
    创建存储过程,存储过程是保存起来的可以接受和返回用户提供的参数的 Transact-SQL 语句的集合。可以创建一个过程供永久使用,或在一个会话中临时使用(局部临时过程),或在所有会话中临时使用(全局临时过程)。也可以创建在 Microsoft SQL Server启动时自动运行的存储过程。

    语法
    CREATE PROC [ EDURE ] procedure_name [ ; number ]
        [ { @parameter data_type }
            [ VARYING ] [ = default ] [ OUTPUT ]
        ] [ ,...n ]

    [ WITH
        { RECOMPILE | ENCRYPTION | RECOMPILE , ENCRYPTION } ]

    [ FOR REPLICATION ]

    AS sql_statement [ ...n ]


    参数
    procedure_name

        新存储过程的名称。过程名必须符合标识符规则,且对于数据库及其所有者必须唯一。有关更多信息,请参见使用标识符。
        要创建局部临时过程,可以在 procedure_name 前面加一个编号符 (#procedure_name),要创建全局临时过程,可以在 procedure_name 前面加两个编号符 (##procedure_name)。完整的名称(包括 # 或 ##)不能超过 128 个字符。指定过程所有者的名称是可选的。

    ;number
        是可选的整数,用来对同名的过程分组,以便用一条 DROP PROCEDURE 语句即可将同组的过程一起除去。例如,名为 orders 的应用程序使用的过程可以命名为 orderproc;1、orderproc;2 等。DROP PROCEDURE orderproc 语句将除去整个组。如果名称中包含定界标识符,则数字不应包含在标识符中,只应在 procedure_name 前后使用适当的定界符。

    @parameter

    过程中的参数。在 CREATE PROCEDURE 语句中可以声明一个或多个参数。用户必须在执行过程时提供每个所声明参数的值(除非定义了该参数的默认值)。存储过程最多可以有 2.100 个参数。

    使用 @ 符号作为第一个字符来指定参数名称。参数名称必须符合标识符的规则。每个过程的参数仅用于该过程本身;相同的参数名称可以用在其它过程中。默认情况下,参数只能代替常量,而不能用于代替表名、列名或其它数据库对象的名称。有关更多信息,请参见 EXECUTE。

    data_type

    参数的数据类型。所有数据类型(包括 text、ntext 和 image)均可以用作存储过程的参数。不过,cursor 数据类型只能用于 OUTPUT 参数。如果指定的数据类型为 cursor,也必须同时指定 VARYING 和 OUTPUT 关键字。有关 SQL Server 提供的数据类型及其语法的更多信息,请参见数据类型。


    说明  对于可以是 cursor 数据类型的输出参数,没有最大数目的限制。


    VARYING

    指定作为输出参数支持的结果集(由存储过程动态构造,内容可以变化)。仅适用于游标参数。

    default

    参数的默认值。如果定义了默认值,不必指定该参数的值即可执行过程。默认值必须是常量或 NULL。如果过程将对该参数使用 LIKE 关键字,那么默认值中可以包含通配符(%、_、[] 和 [^])。

    OUTPUT

    表明参数是返回参数。该选项的值可以返回给 EXEC[UTE]。使用 OUTPUT 参数可将信息返回给调用过程。Text、ntext 和 image 参数可用作 OUTPUT 参数。使用 OUTPUT 关键字的输出参数可以是游标占位符。

    n

    表示最多可以指定 2.100 个参数的占位符。

    {RECOMPILE | ENCRYPTION | RECOMPILE, ENCRYPTION}

    RECOMPILE 表明 SQL Server 不会缓存该过程的计划,该过程将在运行时重新编译。在使用非典型值或临时值而不希望覆盖缓存在内存中的执行计划时,请使用 RECOMPILE 选项。

    ENCRYPTION 表示 SQL Server 加密 syscomments 表中包含 CREATE PROCEDURE 语句文本的条目。使用 ENCRYPTION 可防止将过程作为 SQL Server 复制的一部分发布。


    说明  在升级过程中,SQL Server 利用存储在 syscomments 中的加密注释来重新创建加密过程。


    FOR REPLICATION

    指定不能在订阅服务器上执行为复制创建的存储过程。.使用 FOR REPLICATION 选项创建的存储过程可用作存储过程筛选,且只能在复制过程中执行。本选项不能和 WITH RECOMPILE 选项一起使用。

    AS

    指定过程要执行的操作。

    sql_statement

    过程中要包含的任意数目和类型的 Transact-SQL 语句。但有一些限制。

    n

    是表示此过程可以包含多条 Transact-SQL 语句的占位符。

    注释
    存储过程的最大大小为 128 MB。

    用户定义的存储过程只能在当前数据库中创建(临时过程除外,临时过程总是在 tempdb 中创建)。在单个批处理中,CREATE PROCEDURE 语句不能与其它 Transact-SQL 语句组合使用。

    默认情况下,参数可为空。如果传递 NULL 参数值并且该参数在 CREATE 或 ALTER TABLE 语句中使用,而该语句中引用的列又不允许使用 NULL,则 SQL Server 会产生一条错误信息。为了防止向不允许使用 NULL 的列传递 NULL 参数值,应向过程中添加编程逻辑或为该列使用默认值(使用 CREATE 或 ALTER TABLE 的 DEFAULT 关键字)。

    建议在存储过程的任何 CREATE TABLE 或 ALTER TABLE 语句中都为每列显式指定 NULL 或 NOT NULL,例如在创建临时表时。ANSI_DFLT_ON 和 ANSI_DFLT_OFF 选项控制 SQL Server 为列指派 NULL 或 NOT NULL 特性的方式(如果在 CREATE TABLE 或 ALTER TABLE 语句中没有指定的话)。如果某个连接执行的存储过程对这些选项的设置与创建该过程的连接的设置不同,则为第二个连接创建的表列可能会有不同的为空性,并且表现出不同的行为方式。如果为每个列显式声明了 NULL 或 NOT NULL,那么将对所有执行该存储过程的连接使用相同的为空性创建临时表。

    在创建或更改存储过程时,SQL Server 将保存 SET QUOTED_IDENTIFIER 和 SET ANSI_NULLS 的设置。执行存储过程时,将使用这些原始设置。因此,所有客户端会话的 SET QUOTED_IDENTIFIER 和 SET ANSI_NULLS 设置在执行存储过程时都将被忽略。在存储过程中出现的 SET QUOTED_IDENTIFIER 和 SET ANSI_NULLS 语句不影响存储过程的功能。

    其它 SET 选项(例如 SET ARITHABORT、SET ANSI_WARNINGS 或 SET ANSI_PADDINGS)在创建或更改存储过程时不保存。如果存储过程的逻辑取决于特定的设置,应在过程开头添加一条 SET 语句,以确保设置正确。从存储过程中执行 SET 语句时,该设置只在存储过程完成之前有效。之后,设置将恢复为调用存储过程时的值。这使个别的客户端可以设置所需的选项,而不会影响存储过程的逻辑。


    说明  SQL Server 是将空字符串解释为单个空格还是解释为真正的空字符串,由兼容级别设置控制。如果兼容级别小于或等于 65,SQL Server 就将空字符串解释为单个空格。如果兼容级别等于 70,则 SQL Server 将空字符串解释为空字符串。有关更多信息,请参见 sp_dbcmptlevel。


    获得有关存储过程的信息
    若要显示用来创建过程的文本,请在过程所在的数据库中执行 sp_helptext,并使用过程名作为参数。


    说明  使用 ENCRYPTION 选项创建的存储过程不能使用 sp_helptext 查看。


    若要显示有关过程引用的对象的报表,请使用 sp_depends。

    若要为过程重命名,请使用 sp_rename。

    引用对象
    SQL Server 允许创建的存储过程引用尚不存在的对象。在创建时,只进行语法检查。执行时,如果高速缓存中尚无有效的计划,则编译存储过程以生成执行计划。只有在编译过程中才解析存储过程中引用的所有对象。因此,如果语法正确的存储过程引用了不存在的对象,则仍可以成功创建,但在运行时将失败,因为所引用的对象不存在。有关更多信息,请参见延迟名称解析和编译。

    延迟名称解析和兼容级别
    SQL Server 允许 Transact-SQL 存储过程在创建时引用不存在的表。这种能力称为延迟名称解析。不过,如果 Transact-SQL 存储过程引用了该存储过程中定义的表,而兼容级别设置(通过执行 sp_dbcmptlevel 来设置)为 65,则在创建时会发出警告信息。而如果在运行时所引用的表不存在,将返回错误信息。有关更多信息,请参见 sp_dbcmptlevel 和延迟名称解析和编译。

    执行存储过程
    成功执行 CREATE PROCEDURE 语句后,过程名称将存储在 sysobjects 系统表中,而 CREATE PROCEDURE 语句的文本将存储在 syscomments 中。第一次执行时,将编译该过程以确定检索数据的最佳访问计划。

    使用 cursor 数据类型的参数
    存储过程只能将 cursor 数据类型用于 OUTPUT 参数。如果为某个参数指定了 cursor 数据类型,也必须指定 VARYING 和 OUTPUT 参数。如果为某个参数指定了 VARYING 关键字,则数据类型必须是 cursor,并且必须指定 OUTPUT 关键字。


    说明  cursor 数据类型不能通过数据库 API(例如 OLE DB、ODBC、ADO 和 DB-Library)绑定到应用程序变量上。因为必须先绑定 OUTPUT 参数,应用程序才可以执行存储过程,所以带有 cursor OUTPUT 参数的存储过程不能通过数据库 API 调用。只有将 cursor OUTPUT 变量赋值给 Transact-SQL 局部 cursor 变量时,才可以通过 Transact-SQL 批处理、存储过程或触发器调用这些过程。


    Cursor 输出参数
    在执行过程时,以下规则适用于 cursor 输出参数:

    对于只进游标,游标的结果集中返回的行只是那些存储过程执行结束时处于或超出游标位置的行,例如:
    在过程中的名为 RS 的 100 行结果集上打开一个非滚动游标。


    过程提取结果集 RS 的头 5 行。


    过程返回到其调用者。


    返回到调用者的结果集 RS 由 RS 的第 6 到 100 行组成,调用者中的游标处于 RS 的第一行之前。
    对于只进游标,如果存储过程完成后,游标位于第一行的前面,则整个结果集将返回给调用批处理、存储过程或触发器。返回时,游标将位于第一行的前面。


    对于只进游标,如果存储过程完成后,游标的位置超出最后一行的结尾,则为调用批处理、存储过程或触发器返回空结果集。

    说明  空结果集与空值不同。

    对于可滚动游标,在存储过程执行结束时,结果集中的所有行均会返回给调用批处理、存储过程或触发器。返回时,游标保留在过程中最后一次执行提取时的位置。


    对于任意类型的游标,如果游标关闭,则将空值传递回调用批处理、存储过程或触发器。如果将游标指派给一个参数,但该游标从未打开过,也会出现这种情况。

    说明  关闭状态只有在返回时才有影响。例如,可以在过程中关闭游标,稍后再打开游标,然后将该游标的结果集返回给调用批处理、存储过程或触发器。


    临时存储过程
    SQL Server 支持两种临时过程:局部临时过程和全局临时过程。局部临时过程只能由创建该过程的连接使用。全局临时过程则可由所有连接使用。局部临时过程在当前会话结束时自动除去。全局临时过程在使用该过程的最后一个会话结束时除去。通常是在创建该过程的会话结束时。

    临时过程用 # 和 ## 命名,可以由任何用户创建。创建过程后,局部过程的所有者是唯一可以使用该过程的用户。执行局部临时过程的权限不能授予其他用户。如果创建了全局临时过程,则所有用户均可以访问该过程,权限不能显式废除。只有在 tempdb 数据库中具有显式 CREATE PROCEDURE 权限的用户,才可以在该数据库中显式创建临时过程(不使用编号符命名)。可以授予或废除这些过程中的权限。


    说明  频繁使用临时存储过程会在 tempdb 中的系统表上产生争用,从而对性能产生负面影响。建议使用 sp_executesql 代替。sp_executesql 不在系统表中存储数据,因此可以避免这一问题。


    自动执行存储过程
    SQL Server 启动时可以自动执行一个或多个存储过程。这些存储过程必须由系统管理员创建,并在 sysadmin 固定服务器角色下作为后台过程执行。这些过程不能有任何输入参数。

    对启动过程的数目没有限制,但是要注意,每个启动过程在执行时都会占用一个连接。如果必须在启动时执行多个过程,但不需要并行执行,则可以指定一个过程作为启动过程,让该过程调用其它过程。这样就只占用一个连接。

    在启动时恢复了最后一个数据库后,即开始执行存储过程。若要跳过这些存储过程的执行,请将启动参数指定为跟踪标记 4022。如果以最低配置启动 SQL Server(使用 -f 标记),则启动存储过程也不会执行。有关更多信息,请参见跟踪标记。

    若要创建启动存储过程,必须作为 sysadmin 固定服务器角色的成员登录,并在 master 数据库中创建存储过程。

    使用 sp_procoption 可以:

    将现有存储过程指定为启动过程。


    停止在 SQL Server 启动时执行过程。


    查看 SQL Server 启动时执行的所有过程的列表。
    存储过程嵌套
    存储过程可以嵌套,即一个存储过程可以调用另一个存储过程。在被调用过程开始执行时,嵌套级将增加,在被调用过程执行结束后,嵌套级将减少。如果超出最大的嵌套级,会使整个调用过程链失败。可用 @@NESTLEVEL 函数返回当前的嵌套级。

    若要估计编译后的存储过程大小,请使用下列性能监视计数器。

    性能监视器对象名 性能监视计数器名称
    SQLServer:缓冲区管理器 高速缓存大小(页面数)
    SQLServer:高速缓存管理器 高速缓存命中率
      高速缓存页
      高速缓存对象计数*


    * 各种分类的高速缓存对象均可以使用这些计数器,包括特殊 sql、准备 sql、过程、触发器等。

    有关更多信息,请参见 SQL Server:Buffer Manager 对象和 SQL Server:Cache Manager 对象。

    sql_statement 限制
    除了 SET SHOWPLAN_TEXT 和 SET SHOWPLAN_ALL 之外(这两个语句必须是批处理中仅有的语句),任何 SET 语句均可以在存储过程内部指定。所选择的 SET 选项在存储过程执行过程中有效,之后恢复为原来的设置。

    如果其他用户要使用某个存储过程,那么在该存储过程内部,一些语句使用的对象名必须使用对象所有者的名称限定。这些语句包括:

    ALTER TABLE


    CREATE INDEX


    CREATE TABLE


    所有 DBCC 语句


    DROP TABLE


    DROP INDEX


    TRUNCATE TABLE


    UPDATE STATISTICS
    权限
    CREATE PROCEDURE 的权限默认授予 sysadmin 固定服务器角色成员和 db_owner 和 db_ddladmin 固定数据库角色成员。sysadmin 固定服务器角色成员和 db_owner 固定数据库角色成员可以将 CREATE PROCEDURE 权限转让给其他用户。执行存储过程的权限授予过程的所有者,该所有者可以为其它数据库用户设置执行权限。

    示例
    A. 使用带有复杂 SELECT 语句的简单过程
    下面的存储过程从四个表的联接中返回所有作者(提供了姓名)、出版的书籍以及出版社。该存储过程不使用任何参数。

    USE pubs
    IF EXISTS (SELECT name FROM sysobjects
             WHERE name = 'au_info_all' AND type = 'P')
       DROP PROCEDURE au_info_all
    GO
    CREATE PROCEDURE au_info_all
    AS
    SELECT au_lname, au_fname, title, pub_name
       FROM authors a INNER JOIN titleauthor ta
          ON a.au_id = ta.au_id INNER JOIN titles t
          ON t.title_id = ta.title_id INNER JOIN publishers p
          ON t.pub_id = p.pub_id
    GO

    au_info_all 存储过程可以通过以下方法执行:

    EXECUTE au_info_all
    -- Or
    EXEC au_info_all

    如果该过程是批处理中的第一条语句,则可使用:

    au_info_all

    B. 使用带有参数的简单过程
    下面的存储过程从四个表的联接中只返回指定的作者(提供了姓名)、出版的书籍以及出版社。该存储过程接受与传递的参数精确匹配的值。

    USE pubs
    IF EXISTS (SELECT name FROM sysobjects
             WHERE name = 'au_info' AND type = 'P')
       DROP PROCEDURE au_info
    GO
    USE pubs
    GO
    CREATE PROCEDURE au_info
       @lastname varchar(40),
       @firstname varchar(20)
    AS
    SELECT au_lname, au_fname, title, pub_name
       FROM authors a INNER JOIN titleauthor ta
          ON a.au_id = ta.au_id INNER JOIN titles t
          ON t.title_id = ta.title_id INNER JOIN publishers p
          ON t.pub_id = p.pub_id
       WHERE  au_fname = @firstname
          AND au_lname = @lastname
    GO

    au_info 存储过程可以通过以下方法执行:

    EXECUTE au_info 'Dull', 'Ann'
    -- Or
    EXECUTE au_info @lastname = 'Dull', @firstname = 'Ann'
    -- Or
    EXECUTE au_info @firstname = 'Ann', @lastname = 'Dull'
    -- Or
    EXEC au_info 'Dull', 'Ann'
    -- Or
    EXEC au_info @lastname = 'Dull', @firstname = 'Ann'
    -- Or
    EXEC au_info @firstname = 'Ann', @lastname = 'Dull'

    如果该过程是批处理中的第一条语句,则可使用:

    au_info 'Dull', 'Ann'
    -- Or
    au_info @lastname = 'Dull', @firstname = 'Ann'
    -- Or
    au_info @firstname = 'Ann', @lastname = 'Dull'

    C. 使用带有通配符参数的简单过程
    下面的存储过程从四个表的联接中只返回指定的作者(提供了姓名)、出版的书籍以及出版社。该存储过程对传递的参数进行模式匹配,如果没有提供参数,则使用预设的默认值。

    USE pubs
    IF EXISTS (SELECT name FROM sysobjects
          WHERE name = 'au_info2' AND type = 'P')
       DROP PROCEDURE au_info2
    GO
    USE pubs
    GO
    CREATE PROCEDURE au_info2
       @lastname varchar(30) = 'D%',
       @firstname varchar(18) = '%'
    AS
    SELECT au_lname, au_fname, title, pub_name
    FROM authors a INNER JOIN titleauthor ta
       ON a.au_id = ta.au_id INNER JOIN titles t
       ON t.title_id = ta.title_id INNER JOIN publishers p
       ON t.pub_id = p.pub_id
    WHERE au_fname LIKE @firstname
       AND au_lname LIKE @lastname
    GO

    au_info2 存储过程可以用多种组合执行。下面只列出了部分组合:

    EXECUTE au_info2
    -- Or
    EXECUTE au_info2 'Wh%'
    -- Or
    EXECUTE au_info2 @firstname = 'A%'
    -- Or
    EXECUTE au_info2 '[CK]ars[OE]n'
    -- Or
    EXECUTE au_info2 'Hunter', 'Sheryl'
    -- Or
    EXECUTE au_info2 'H%', 'S%'

    D. 使用 OUTPUT 参数
    OUTPUT 参数允许外部过程、批处理或多条 Transact-SQL 语句访问在过程执行期间设置的某个值。下面的示例创建一个存储过程 (titles_sum),并使用一个可选的输入参数和一个输出参数。

    首先,创建过程:

    USE pubs
    GO
    IF EXISTS(SELECT name FROM sysobjects
          WHERE name = 'titles_sum' AND type = 'P')
       DROP PROCEDURE titles_sum
    GO
    USE pubs
    GO
    CREATE PROCEDURE titles_sum @@TITLE varchar(40) = '%', @@SUM money OUTPUT
    AS
    SELECT 'Title Name' = title
    FROM titles
    WHERE title LIKE @@TITLE
    SELECT @@SUM = SUM(price)
    FROM titles
    WHERE title LIKE @@TITLE
    GO

    接下来,将该 OUTPUT 参数用于控制流语言。


    说明  OUTPUT 变量必须在创建表和使用该变量时都进行定义。


    参数名和变量名不一定要匹配,不过数据类型和参数位置必须匹配(除非使用 @@SUM = variable 形式)。

    DECLARE @@TOTALCOST money
    EXECUTE titles_sum 'The%', @@TOTALCOST OUTPUT
    IF @@TOTALCOST < 200
    BEGIN
       PRINT ' '
       PRINT 'All of these titles can be purchased for less than $200.'
    END
    ELSE
       SELECT 'The total cost of these titles is $'
             + RTRIM(CAST(@@TOTALCOST AS varchar(20)))

    下面是结果集:

    Title Name                                                              
    ------------------------------------------------------------------------
    The Busy Executive's Database Guide
    The Gourmet Microwave
    The Psychology of Computer Cooking

    (3 row(s) affected)

    Warning, null value eliminated from aggregate.
     
    All of these titles can be purchased for less than $200.

    E. 使用 OUTPUT 游标参数
    OUTPUT 游标参数用来将存储过程的局部游标传递回调用批处理、存储过程或触发器。

    首先,创建以下过程,在 titles 表上声明并打开一个游标:

    USE pubs
    IF EXISTS (SELECT name FROM sysobjects
          WHERE name = 'titles_cursor' and type = 'P')
    DROP PROCEDURE titles_cursor
    GO
    CREATE PROCEDURE titles_cursor @titles_cursor CURSOR VARYING OUTPUT
    AS
    SET @titles_cursor = CURSOR
    FORWARD_ONLY STATIC FOR
    SELECT *
    FROM titles

    OPEN @titles_cursor
    GO

    接下来,执行一个批处理,声明一个局部游标变量,执行上述过程以将游标赋值给局部变量,然后从该游标提取行。

    USE pubs
    GO
    DECLARE @MyCursor CURSOR
    EXEC titles_cursor @titles_cursor = @MyCursor OUTPUT
    WHILE (@@FETCH_STATUS = 0)
    BEGIN
       FETCH NEXT FROM @MyCursor
    END
    CLOSE @MyCursor
    DEALLOCATE @MyCursor
    GO

    F. 使用 WITH RECOMPILE 选项
    如果为过程提供的参数不是典型的参数,并且新的执行计划不应高速缓存或存储在内存中,WITH RECOMPILE 子句会很有帮助。

    USE pubs
    IF EXISTS (SELECT name FROM sysobjects
          WHERE name = 'titles_by_author' AND type = 'P')
       DROP PROCEDURE titles_by_author
    GO
    CREATE PROCEDURE titles_by_author @@LNAME_PATTERN varchar(30) = '%'
    WITH RECOMPILE
    AS
    SELECT RTRIM(au_fname) + ' ' + RTRIM(au_lname) AS 'Authors full name',
       title AS Title
    FROM authors a INNER JOIN titleauthor ta
       ON a.au_id = ta.au_id INNER JOIN titles t
       ON ta.title_id = t.title_id
    WHERE au_lname LIKE @@LNAME_PATTERN
    GO

    G. 使用 WITH ENCRYPTION 选项
    WITH ENCRYPTION 子句对用户隐藏存储过程的文本。下例创建加密过程,使用 sp_helptext 系统存储过程获取关于加密过程的信息,然后尝试直接从 syscomments 表中获取关于该过程的信息。

    IF EXISTS (SELECT name FROM sysobjects
          WHERE name = 'encrypt_this' AND type = 'P')
       DROP PROCEDURE encrypt_this
    GO
    USE pubs
    GO
    CREATE PROCEDURE encrypt_this
    WITH ENCRYPTION
    AS
    SELECT *
    FROM authors
    GO

    EXEC sp_helptext encrypt_this

    下面是结果集:

    The object's comments have been encrypted.

    接下来,选择加密存储过程内容的标识号和文本。

    SELECT c.id, c.text
    FROM syscomments c INNER JOIN sysobjects o
       ON c.id = o.id
    WHERE o.name = 'encrypt_this'

    下面是结果集:


    说明  text 列的输出显示在单独一行中。执行时,该信息将与 id 列信息出现在同一行中。


    id         text                                                       
    ---------- ------------------------------------------------------------
    1413580074 ?????????????????????????????????e??????????????????????????????????????????????????????????????????????????

    (1 row(s) affected)

    H. 创建用户定义的系统存储过程
    下面的示例创建一个过程,显示表名以 emp 开头的所有表及其对应的索引。如果没有指定参数,该过程将返回表名以 sys 开头的所有表(及索引)。

    IF EXISTS (SELECT name FROM sysobjects
          WHERE name = 'sp_showindexes' AND type = 'P')
       DROP PROCEDURE sp_showindexes
    GO
    USE master
    GO
    CREATE PROCEDURE sp_showindexes
       @@TABLE varchar(30) = 'sys%'
    AS
    SELECT o.name AS TABLE_NAME,
       i.name AS INDEX_NAME,
       indid AS INDEX_ID
    FROM sysindexes i INNER JOIN sysobjects o
       ON o.id = i.id
    WHERE o.name LIKE @@TABLE
    GO        
    USE pubs
    EXEC sp_showindexes 'emp%'
    GO

    下面是结果集:

    TABLE_NAME       INDEX_NAME       INDEX_ID
    ---------------- ---------------- ----------------
    employee         employee_ind     1
    employee         PK_emp_id        2

    (2 row(s) affected)

    I. 使用延迟名称解析
    下面的示例显示四个过程以及延迟名称解析的各种可能使用方式。尽管引用的表或列在编译时不存在,但每个存储过程都可创建。

    IF EXISTS (SELECT name FROM sysobjects
          WHERE name = 'proc1' AND type = 'P')
       DROP PROCEDURE proc1
    GO
    -- Creating a procedure on a nonexistent table.
    USE pubs
    GO
    CREATE PROCEDURE proc1
    AS
       SELECT *
       FROM does_not_exist
    GO 
    -- Here is the statement to actually see the text of the procedure.
    SELECT o.id, c.text
    FROM sysobjects o INNER JOIN syscomments c
       ON o.id = c.id
    WHERE o.type = 'P' AND o.name = 'proc1'
    GO
    USE master
    GO
    IF EXISTS (SELECT name FROM sysobjects
          WHERE name = 'proc2' AND type = 'P')
       DROP PROCEDURE proc2
    GO
    -- Creating a procedure that attempts to retrieve information from a
    -- nonexistent column in an existing table.
    USE pubs
    GO
    CREATE PROCEDURE proc2
    AS
       DECLARE @middle_init char(1)
       SET @middle_init = NULL
       SELECT au_id, middle_initial = @middle_init
       FROM authors
    GO 
    -- Here is the statement to actually see the text of the procedure.
    SELECT o.id, c.text
    FROM sysobjects o INNER JOIN syscomments c
       ON o.id = c.id
    WHERE o.type = 'P' and o.name = 'proc2'

    posted @ 2008-11-19 13:49 jiafang83 阅读(598) | 评论 (0)编辑 收藏
    转载:http://tgyd2006.javaeye.com/blog/169820

    web.xml元素介绍
    每一个站的WEB-INF下都有一个web.xml的设定文件,它提供了我们站台的配置设定.

    web.xml定义:
    .站台的名称和说明
    .针对环境参数(Context)做初始化工作
    .Servlet的名称和映射
    .Session的设定
    .Tag library的对映
    .JSP网页设定
    .Mime Type处理
    .错误处理
    .利用JDNI取得站台资源

    要了解web.xml的设定值,必须了解它的schema,从web.xml中知道它的schema是由Sum Microsystems公司定制的,如果你想更为详细的了解它,
    可以到http://java.sun.com/xml/ns/j2ee/web-mapp_2_4.xsd网页,那里有更为详细的介绍。这里我介绍我们平常见得最都的.

    <?xml version="1.0" encoding="ISO-8859-1"?>

    <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
        version="2.4">
    <web-app>
    这是一般在写XML时所做的声明,定义了XML的版本,编码格式,还有重要的指明schema的来源,为http://java.sun.com/xml/ns/j2ee
    /web-app_2_4.xsd.


    <description>,<display-name>,<icon>
    ____________________________________________

    <description>站台描述</discription>
    对站台做出描述.

    <display-name>站台名称</display-name>
    定义站台的名称.

    <icon>
    icon元素包含small-icon和large-icon两个子元素.用来指定web站台中小图标和大图标的路径.
    <small-icon>/路径/smallicon.gif</small-icon>
    small-icon元素应指向web站台中某个小图标的路径,大小为16 X 16 pixel,但是图象文件必须为GIF或JPEG格式,扩展名必须为:.gif或
    .jpg.

    <large-icon>/路径/largeicon-jpg</large-icon>
    large-icon元素应指向web站台中某个大图表路径,大小为32 X 32 pixel,但是图象文件必须为GIF或JPEG的格式,扩展名必须为; gif
    或jpg.
    范例:
    <display-name>Develop Example</display-name>
    <description>JSP 2.0 Tech Book's Examples</description>
    <icon>
       <small-icon>/images/small.gif</small-icon>
       <large-icon>/images/large.gir</large-icon>
    </icon>


    <distributable>
    ______________________________________

    <distributable>
    distributable 元素为空标签,它的存在与否可以指定站台是否可分布式处理.如果web.xml中出现这个元素,则代表站台在开发时已经
    被设计为能在多个JSP Container 之间分散执行.
    范例:
    <distributable/>


    <context-param>
    ___________________________________

    <context-param>
    context-param 元素用来设定web站台的环境参数(context),它包含两个子元素:
    param-name和param-value.
    <param-name>参数名称</param-name>
    设定Context名称
    <param-value>值</param-value>
    设定Context名称的值
    </context-param>
    范例:
    <context-param>
       <param-name>param_name</param-name>
       <param-value>param_value</param-value>
    </context-param>
    此所设定的参数,在JSP网页中可以使用下列方法来取得:
    ${initParam.param_name}
    若在Servlet可以使用下列方法来获得:
    String param_name=getServletContext().getInitParamter("param_name");


    <filter>
    _________________________________
    filter元素用来声明filter的相关设定.filter元素除了下面介绍的的子元素之外,还包括<servlet>介绍过的<icon>,<display-name>
    ,<description>,<init-param>,其用途一样.
    <filter-name>Filter的名称</filter-name>
    定义Filter的名称.
    <filter-class>Filter的类名称</filter-class>
    定义Filter的类名称.例如:com.foo.hello
    </filter>
    范例:
    <filter>
    <filter-name>setCharacterEncoding</filter-name>
    <filter-class>coreservlet.javaworld.CH11.SetCharacterEncodingFilter</filter-class>
    <init-param>
         <param-name>encoding</param-name>
         <param-value>GB2312</param-value>
    </init-param>
    </filter>


    <filter-mapping>
    ______________________________________
    <filter-mapping>
    filter-mapping 元素的两个主要子元素filter-name和url-pattern.用来定义Filter所对应的URL.
    <filter-name>Filter的名称</filter-name>
    定义Filter的名称.
    <url-pattern>URL</url-pattern>
    Filter所对应的RUL.例如:<url-pattern>/Filter/Hello</url-pattern>

    <servlet-name>Servlet的名称<servlet-name>
    定义servlet的名称.
    <dispatcher>REQUEST|INCLUDE|FORWARD|ERROR</disaptcher>
    设定Filter对应的请求方式,有RQUEST,INCLUDE,FORWAR,ERROR四种,默认为REQUEST.
    </filter-mapping>
    范例:
    <filter-mapping>
       <filter-name>GZIPEncoding</filter-name>
       <url-pattern>/*</url-pattern>
    </filter-mapping>


    <listener>
    ___________________________________________
    <listener>
    listener元素用来定义Listener接口,它的主要子元素为<listener-class>
    <listen-class>Listener的类名称</listener-class>
    定义Listener的类名称.例如: com.foo.hello
    <listener>
    范例:
    <listener>
    <listener-class>coreservlet.javaworld.CH11.ContenxtListener</listener-class>
    </listener>


    <servlet-mapping>
    _____________________________________________
    servlet-mapping元素包含两个子元素servlet-name和url-pattern.用来定义servlet所对应URL.
    <servlet-name>Servlet的名称</servlet-name>
    定义Servlet的名称.
    <url-pattern>Servlet URL</url-pattern>
    定义Servlet所对应的RUL.例如:<url-pattern>/Servlet/Hello</url-pattern>
    </servlet-mapping>
    范例:
    <servlet-mapping>
       <servlet-name>LoginChecker</servlet-name>
       <url-pattern>/LoginChecker</url-pattern>
    </servlet-mapping>


    <session-cofing>
    __________________________________
    <session-config>
    session-config包含一个子元素session-timeout.定义web站台中的session参数.
    <session-timeout>分钟</session-timeout>
    定义这个web站台所有session的有效期限.单位为分钟.
    </session-config>
    范例:
    <session-config>
       <session-timeout>20</session-timeout>
    </session-config>


    <mime-mapping>
    ___________________________________________________
    <mima-mapping>
    mime-mapping包含两个子元素extension和mime-type.定义某一个扩展名和某一MIME Type做对映.
    <extension>扩展名名称</extension>
    扩展名称
    <mime-type>MIME格式</mime-type>
    MIME格式.
    </mime-mapping>
    范例:
    <mime-mapping>
       <extension>doc</extension>
       <mime-type>application/vnd.ms-word</mime-type>
    </mime-mapping>
    <mime-mapping>
       <extension>xls</extension>
       <mime-type>application/vnd.ms-excel</mime-type>
    </mime-mapping>
    <mime-mapping>
       <extension>ppt</extesnion>
       <mime-type>application/vnd.ms-powerpoint</mime-type>
    </mime-mapping>


    <welcome-file-list>
    _____________________________________________
    <welcome-file-list>
    welcome-file-list包含一个子元素welcome-file.用来定义首页列单.
    <welcome-file>用来指定首页文件名称</welcome-flie>
    welcome-file用来指定首页文件名称.我们可以用<welcome-file>指定几个首页,而服务器会依照设定的顺序来找首页.
    范例:
    <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.htm</welcome-file>
    </welcome-file-list>


    <error-page>
    _________________________
    <error-page>
    error-page元素包含三个子元素error-code,exception-type和location.将错误代码(Error Code)或异常(Exception)的种类对应
    到web站台资源路径.
    <error-code>错误代码</error-code>
    HTTP Error code,例如: 404
    <exception-type>Exception</exception-type>
    一个完整名称的Java异常类型
    <location>/路径</location>
    在web站台内的相关资源路径
    </error-page>
    范例:
    <error-page>
       <error-code>404</error-code>
       <location>/error404.jsp</location>
    </error-page>
    <error-page>
       <exception-type>java.lang.Exception</exception-type>
       <location>/except.jsp</location>
    </error-page>


    <jsp-config>
    _______________________________________________
    <jsp-config>
    jsp-config元素主要用来设定JSP的相关配置,<jsp:config>包括<taglib>和<jsp-property-group>两个子元素.其中<taglib>元素
    在JSP 1.2时就已经存在了;而<jsp-property-group>是JSP 2.0新增的元素.

    <taglib>
    taglib元素包含两个子元素taglib-uri和taglib-location.用来设定JSP网页用到的Tag Library路径.
    <taglib-uri>URI</taglib-uri>
       taglib-uri定义TLD文件的URI,JSP网页的taglib指令可以经由这个URI存取到TLD文件.
    <taglib-location>/WEB-INF/lib/xxx.tld</taglib-laction>
       TLD文件对应Web站台的存放位置.
    </taglib>

    <jsp-property-group>
    jsp-property-group元素包含8个元素,分别为:
    <description>Description</descrition>
    此设定的说明

    <display-name>Name</display-name>
    此设定的名称

    <url-pattern>URL</url-pattern>
    设定值所影响的范围,如:/CH2 或者/*.jsp

    <el-ignored>true|false</el-ignored>
    若为true,表示不支持EL语法.

    <scripting-invalid>true|false</scripting-invalid>
    若为true表示不支持<%scription%>语法.

    <page-encoding>encoding</page-encoding>
    设定JSP网页的编码

    <include-prelude>.jspf</include-prelude>
    设置JSP网页的抬头,扩展名为.jspf

    <include-coda>.jspf</include-coda>
    设置JSP网页的结尾,扩展名为.jspf
    </jsp-property-group>
    </jsp-config>
    范例:
    <jsp-config>
    <taglib>
       <taglib-uri>Taglib</taglib-uri>
       <taglib-location>/WEB-INF/tlds/MyTaglib.tld</taglib-location>
    </taglib>
    <jsp-property-group>
       <description>
          Special property group for JSP Configuration JSP example.
       </description>
       <display-name>JSPConfiguration</display-name>
       <uri-pattern>/*</uri-pattern>
       <el-ignored>true</el-ignored>
       <page-encoding>GB2312</page-encoding>
       <scripting-inivalid>true</scripting-inivalid>
       ............
    </jsp-property-group>
    </jsp-config>


    <resource-ref>
    ________________________________________________
    <resource-ref>
    resource-ref元素包括五个子元素description,res-ref-name,res-type,res-auth,res-sharing-scope.利用JNDI取得站台可
    利用资源.
    <description>说明</description>
    资源说明

    <rec-ref-name>资源名称</rec-ref-name>
    资源名称

    <res-type>资源种类</res-type>
    资源种类

    <res-auth>Application|Container</res-auth>
    资源由Application或Container来许可

    <res-sharing-scope>Shareable|Unshareable</res-sharing-scope>
    资源是否可以共享.默认值为 Shareable
    范例:
    <resource-ref>
       <description>JNDI JDBC DataSource of JSPBook</description>
       <res-ref-name>jdbc/sample_db</res-ref-name>
       <res-type>javax.sql.DataSoruce</res-type>
       <res-auth>Container</res-auth>
    </resource-ref>
    posted @ 2008-11-18 14:19 jiafang83 阅读(258) | 评论 (0)编辑 收藏
       jforum是一个不错的开源BBS论坛,支持中文,操作方便,容易扩展,是一个不错的选择。通过参考网上的资料,下面给出了jforum与web项目整合的方法:
    1、实现SSO类:

    package net.jforum.sso;

    import javax.servlet.http.Cookie;

    import net.jforum.ControllerUtils;
    import net.jforum.context.RequestContext;
    import net.jforum.entities.UserSession;
    import net.jforum.util.preferences.ConfigKeys;
    import net.jforum.util.preferences.SystemGlobals;
    import org.apache.log4j.Logger;
     
      public class CookieUserSSO implements SSO {     
        
        static final Logger logger = Logger.getLogger(CookieUserSSO.class.getName());     
        
        public String authenticateUser(RequestContext request) { 
             // myapp login cookie, contain logged username     
            Cookie myCookie = ControllerUtils.getCookie("jforumSSOCookieNameUser");     
                 
            String username = null;          
            if (myCookie != null) username = myCookie.getValue();      
            System.out.println("cookie_name1="+myCookie.getName());   
            System.out.println("cookie value1="+myCookie.getValue());  
                 
            if (myCookie == null || username.trim().equals("")) {     
                //JForumExecutionContext.setRedirect(SystemGlobals.getValue(ConfigKeys.SSO_REDIRECT));     
                return null; // no cookie found     
            }      
            System.out.println("cookie_name2="+myCookie.getName());  
            System.out.println("cookie value2="+myCookie.getValue());  
            return username; // jforum username     
        }     
        
        public boolean isSessionValid(UserSession userSession, RequestContext request) {   
      System.out.println("执行isSessionValid方法");
            Cookie SSOCookie = ControllerUtils.getCookie("jforumSSOCookieNameUser"); // myapp login cookie      
                           
            String remoteUser = null;     
                 
            if (SSOCookie != null) remoteUser = SSOCookie.getValue(); //  jforum username     
        
            // user has since logged out     
            if(remoteUser == null &&      
                    userSession.getUserId() != SystemGlobals.getIntValue(ConfigKeys.ANONYMOUS_USER_ID)) {     
                return false;     
            // user has since logged in     
            } else if(remoteUser != null &&      
                    userSession.getUserId() == SystemGlobals.getIntValue(ConfigKeys.ANONYMOUS_USER_ID)) {     
                return false;     
            // user has changed user     
            } else if(remoteUser != null && !remoteUser.equals(userSession.getUsername())) {     
                return false;     
            }     
            return true; // myapp user and forum user the same     
        }     
    }    

    把该类放在jforum\WEB-INF\classes下,然后用javac  -d  .  CookieUserSSO .java 命令编译,.class文件存放在jforum\WEB-INF\classes\net\jforum\sso下。
    2、修改SystemGlobals.properties
       有些JForum版本为jforum-custom.conf文件。
       查找“SSO”字样,找到“SSO / User authentication”配置部分,将其修改为以下内容:
    authentication.type = sso-----------特别注意:sso用小写,不能用大写
    ##...
    sso.implementation = net.jforum.sso.CookieUserSSO----------你自己实现的SSO类
    ##...
    sso.redirect=http://localhost:port/jforum---------------例如:sso.redirect=http://localhost:8082/jforum
    3、在程序的登录或注销部分加入如下代码:
         登录:
    Cookie cookie = new Cookie("jforumSSOCookieNameUser",name);-------name为从登录界面取得的用户名,把它加入到cookie里面
      cookie.setPath("/");
      cookie.setMaxAge(-1);//设置cookie的生命周期为:会话级,即浏览器关闭,该cookie就消失了
      response.addCookie(cookie);

        注销:

      Cookie cookie =  new    Cookie(jforumSSOCookieNameUser, "");
      cookie.setMaxAge(0); // delete the cookie.
      response.addCookie(cookie);

    4、在html/jsp页面加入超链接:
    <a href="/jforum">转到论坛</a>

    这就配置完成了。


    posted @ 2008-11-18 11:39 jiafang83 阅读(1913) | 评论 (0)编辑 收藏

    Cookie[] cookies = request.getCookies();
        if (cookies != null) {
         for (int i = 0; i < cookies.length; i++) {
          cookies[i].setValue(null);
          cookies[i].setMaxAge(0);
          response.addCookie(cookies[i]);
         }
        }

    posted @ 2008-11-17 11:58 jiafang83 阅读(124) | 评论 (0)编辑 收藏
    转发:http://hi.baidu.com/unaras/blog/item/43c8338109cd27dcbd3e1e27.html
    一.什么是cookies?
      大家都知道,浏览器与WEB服务器之间是使用HTTP协议进行通信的,当某个用户发出页面请求时,WEB服务器只是简单的进行响应,然后就关闭与该用户的连接。因此当一个请求发送到WEB服务器时,无论其是否是第一次来访,服务器都会把它当作第一次来对待,这样的不好之处可想而知。为了弥补这个缺陷,Netscape开发出了cookie这个有效的工具来保存某个用户的识别信息,因此人们昵称为“小甜饼”。cookies是一种WEB服务器通过浏览器在访问者的硬盘上存储信息的手段:Netscape Navigator使用一个名为cookies.txt本地文件保存从所有站点接收的Cookie信息;而IE浏览器把Cookie信息保存在类似于C:\\windows\\cookies的目录下。当用户再次访问某个站点时,服务端将要求浏览器查找并返回先前发送的Cookie信息,来识别这个用户。
      cookies给网站和用户带来的好处非常多:
      1、Cookie能使站点跟踪特定访问者的访问次数、最后访问时间和访问者进入站点的路径
      2、Cookie能告诉在线广告商广告被点击的次数,从而可以更精确的投放广告
      3、Cookie有效期限未到时,Cookie能使用户在不键入密码和用户名的情况下进入曾经浏览过的一些站点
      4、Cookie能帮助站点统计用户个人资料以实现各种各样的个性化服务
      在JSP中,我们也可以使用Cookie,来编写一些功能强大的应用程序。
      下面,我想介绍一下如何用JSP创建和处理Cookie。

      二.如何创建Cookie
      说了这么多,大家一定很想知道JSP是如何创建cookie了。JSP是使用如下的语法格式来创建cookie的:
      Cookie cookie_name =new Cookie("Parameter","Value");
      例如:Cookie newCookie =new Cookie("username","waynezheng"); response.addCookie(newCookie);
      解释:JSP是调用Cookie对象相应的构造函数Cookie(name,value)用合适的名字和值来创建Cookie,然后Cookie可以通过HttpServletResponse的addCookie方法加入到Set-Cookie应答头,本例中Cookie对象有两个字符串参数:username,waynezheng。注意,名字和值都不能包含空白字符以及下列字符:@ : ;? , " / [ ] ( ) =
      处理Cookie的属性
      看到这里,有的朋友又要问了:我光知道如何创建Cookie有什么用呀?是呀,光知道如何创建Cookie而不知道怎么使用是不够的。在JSP中,程序是通过cookie.setXXX设置各种属性,用cookie.getXXX读出cookie的属性,现把Cookie的主要属性,及其方法列于下,供大家参考:
      类型方法名方法解释
      String getComment() 返回cookie中注释,如果没有注释的话将返回空值.
      String getDomain() 返回cookie中Cookie适用的域名. 使用getDomain() 方法可以指示浏览器把Cookie返回给同一域内的其他服务器,而通常Cookie只返回给与发送它的服务器名字完全相同的服务器。注意域名必须以点开始(例如.yesky.com)
      int getMaxAge() 返回Cookie过期之前的最大时间,以秒计算。
      String getName() 返回Cookie的名字。名字和值是我们始终关心的两个部分,笔者会在后面详细介绍getName/setName。
      String getPath() 返回Cookie适用的路径。如果不指定路径,Cookie将返回给当前页面所在目录及其子目录下的所有页面。
      boolean getSecure() 如果浏览器通过安全协议发送cookies将返回true值,如果浏览器使用标准协议则返回false值。
      String getValue() 返回Cookie的值。笔者也将在后面详细介绍getValue/setValue。
      int getVersion() 返回Cookie所遵从的协议版本。
      void setComment(String purpose) 设置cookie中注释。
      void setDomain(String pattern) 设置cookie中Cookie适用的域名
      void setMaxAge(int expiry) 以秒计算,设置Cookie过期时间。
      void setPath(String uri) 指定Cookie适用的路径。
      void setSecure(boolean flag) 指出浏览器使用的安全协议,例如HTTPS或SSL。
      void setValue(String newValue) cookie创建后设置一个新的值。
      void setVersion(int v) 设置Cookie所遵从的协议版本。  
      读取客户端的Cookie
      在Cookie发送到客户端前,先要创建一个Cookie,然后用addCookie方法发送一个HTTP Header。JSP将调用request.getCookies()从客户端读入Cookie,getCookies()方法返回一个HTTP请求头中的内容对应的Cookie对象数组。你只需要用循环访问该数组的各个元素,调用getName方法检查各个Cookie的名字,直至找到目标Cookie,然后对该Cookie调用getValue方法取得与指定名字关联的值。
      例如
      <%
       String userName=request.getParameter("username");//从提交的HTML表单中获取,用户名
       Cookie theUsername=new Cookie("username",userName);//以"username",userName值/对创建一个Cookie
                theUsername.setMaxAge(60*60*24*365);
       response.addCookie(theUsername);
      %>
      ..............
      <%
       Cookie myCookie[]=request.getCookies();//创建一个Cookie对象数组
       for(int n=0;n=cookie.length-1;i++);//设立一个循环,来访问Cookie对象数组的每一个元素
       Cookie newCookie= myCookie[n];
       if(newCookie.getName().equals("username")); //判断元素的值是否为username中的值
        {%>
         你好,<%=newCookie.getValue()%>!//如果找到后,向他问好
        <%}
      %>
      设置Cookie的存在时间,及删除Cookie 在JSP中,使用setMaxAge(int expiry)方法来设置Cookie的存在时间,参数expiry应是一个整数。正值表示cookie将在这么多秒以后失效。注意这个值是cookie将要存在的最大时间,而不是cookie现在的存在时间。负值表示当浏览器关闭时,Cookie将会被删除。零值则是要删除该Cookie。如:  
      <%
       Cookie deleteNewCookie=new Cookie("newcookie",null);
       deleteNewCookie.setMaxAge(0);
       deleteNewCookie.setPath("/");
       response.addCookie(deleteNewCookie);
      %>
    posted @ 2008-11-17 11:03 jiafang83 阅读(1371) | 评论 (1)编辑 收藏
    1、简单Bean装配
        <bean    id="foo"    class="com.jiafang.Foo">
        <property    name="name">
            <value>jiafang</value>
        </property>
        </bean>
    2、引用其它Bean
        <bean    id="foo"    class="com.jiafang.Foo">
        <property    name="bar">
            <ref    bean="bar">
        </property>
        </bean>
        <bean    id="bar"    class="com.spring.Bar"    />
    3、内部Bean
        <bean    id="courseService"    class="com.jiafang.CourseService" >
        <property    name="studentService" >
            <bean    class="com.student.StudentService" >
        </property>
        </bean>
    4、装配集合
    4、1 装配List和数组
        <property    name="barList" >
            <list>
                <value>bar1</value>
                <ref    bean="bar2" >------list里的元素可以是任何一种元素,包括<value>、<ref>、甚至是其它<list>
            </list>
        </property>
    4、2 装配Set
        <property    name="barSet" >
            <set>
                <value>bar1</value>
                <ref    bean="bar2" >------set里的元素可以是任何一种元素,包括<value>、<ref>、甚至是其它<set>
            </set>
        </property>
    4、3 装配Map
        <property    name="barMap" >
            <map>
                    <entry    key="key1">------key的值只能是String类型
                        <value>bar1</value>
                    </entry >------entry里的元素可以是任何一种元素,包括<value>、<ref>、甚至是其它<entry>
            </map>
        </property>
    4、4 装配Properties
        <property    name="barProps" >
            <props>
                <prop    key="key1"> bar1 </prop>
                <prop    key="key2"> bar2 </prop>
            </props>
        </property>
    5、设置null
        <property    name="foo">
            <null />
        </property>
    posted @ 2008-11-12 11:13 jiafang83 阅读(267) | 评论 (0)编辑 收藏

    public class Trigon {

     public static void main(String[] args) {
            double x1 = 9;
            double y1 = 9;
            double x2 = 4;
            double y2 = 4;
      
      Point sp = new Point(x1,y1);//sp是直线上的一点
      Point tp = new Point(x2,y2);//tp是直线上的另一点,也是三角形的顶点
      double arrowWidth = 3;   //设置三角形的半边底长
      double arrowHeight = 6; //设置三角形的高

      double angle = Math.atan2(tp.y-sp.y, tp.x-sp.x); //求已知直线的倾斜角
      
      System.out.println("该直线的倾斜角度是:" + angle);

      double point_x1 = tp.x-arrowHeight*Math.cos(angle)-arrowWidth*Math.sin(angle);
      double point_y1 = tp.y-arrowHeight*Math.sin(angle)+arrowWidth*Math.cos(angle);

      double point_x2 =tp.x-arrowHeight*Math.cos(angle)+arrowWidth*Math.sin(angle);
      double point_y2 = tp.y-arrowHeight*Math.sin(angle)-arrowWidth*Math.cos(angle);
      
      Point p1 = new Point(point_x1,point_y1);
      Point p2 = new Point(point_x2,point_y2);
      p1.out();
      p2.out();
     }
    }
    //定义定点类
    class Point{
     double x;
     double y;
     
     public Point(){}
     public Point(double x, double y){
      this.x = x;
      this.y = y;
     }
     
     public void out(){
      System.out.println("该顶点的X坐标:" + x);
      System.out.println("该顶点的Y坐标:" + y);
     }
    }

    参考:http://blog.csdn.net/james999/archive/2008/09/05/2885380.aspx

    posted @ 2008-11-12 10:09 jiafang83 阅读(678) | 评论 (0)编辑 收藏

    public class Test {

     public static void main(String[] args) {
      String s = "GET             /index.html HTTP/1.1";//字符串s由“GET”、“/index.html”和“HTTP/1.1”组成,中间有一个或多个空格
      String tt[] = s.split("\\s{1,}");//按照空格分割字符串,多个空格作为一个空格对字符串进行分割
      for(String str: tt)//增强的for循环
      System.out.println(str);//输出:GET
                                         //  /index.html
                                        //  HTTP/1.1          
      String qq = s.replaceAll(" {2,}", " ");//把字符串s中的多个空格替换为一个空格
      System.out.println(qq);//输出:GET /index.html HTTP/1.1 
      System.out.println(s);//输出:GET             /index.html HTTP/1.1
     }
    }

    posted @ 2008-11-11 17:12 jiafang83 阅读(21314) | 评论 (4)编辑 收藏
    摘自:http://www.blogjava.net/nokiaguy/archive/2008/05/10/199645.html    
        本文将介绍如何在Java中使用正则表达式来处理文本数据。正则表达式就是一个字符串,但和普通的字符串不同的是,正则表达式是对一组相似字符串的抽象,如下面的几个字符串:
     
    a98b   c0912d   c10b   a12345678d   ab
     
        我们仔细分析上面五个字符串,可以看出它们有一个共同特征,就是第一个字符必须是'a'或'c',最后一个字符必须是'b'或'd',而中间的字符是任意多个数字组成(包括0个数字)。因此,我们可以将这五个字符串的共同特点抽象出来,这就产生了一个正则表达式:[ac]\\d*[bd]。而根据这个正则表达式,我们可以写出无穷多个满足条件的字符串。
     
    在Java中使用正则表达式的方法非常多,最简单的就是和字符串一起使用。在String中有四个方法可以使用正则表达式,它们是matches、split、replaceAll和replaceFirst。
     
    一、matches方法
     
    matches方法可以判断当前的字符串是否匹配给定的正则表达式。如果匹配,返回true,否则,返回false。matches方法的定义如下:

    public boolean matches(String regex)
      
      如上面给出的正则表达式我们可以用如下程序验证。
     
    String[] ss = new String[]{"a98b""c0912d",  "c10b",  "a12345678d",  "ab"};
    for(String s: ss)
        System.out.println(s.matches(
    "[ac]\\d*[bd]"));

    输出结果:
     
    true
    true
    true
    true
    true
     
       下面简单解释一下这个正则表达式的含义。如果我们学过编译原理的词法分析,就会很容易理解上面的正则表达式(因为正则表达式的表示方法和词法分析中的表达式类似)。如在 [...]中的相当于或"|",如[abcd]相当于a|b|c|d,也就是a或b或c或d。如上面的正则表达式的开头部分是[ac],就代表着字符串的开头只能是a或c。[bd]表达字符串结尾只能是b或d。而中间的\d表达0-9的数字,由于\在正则表达式中有特殊含义,所以用\\来表示\。而*表示有0或无穷多个(这在词法分析中叫*闭包),由于*跟在\d后面,因此表达有0或无穷多个数字。
     
    二、split方法
     
    split方法使用正则表达式来分割字符串,并以String数组的形式返回分割结果。split有两种重载形式,它们定义如下:
     
    public String[] split(String regex)
    public String[] split(String regex, int limit)

        如下面的代码将使用split的第一种重载形式来分割HTTP请求头的第一行,代码如下:
     
    String s = "GET /index.html HTTP/1.1";
    String ss[] 
    = s.split(" +");
    for(String str: ss)
    System.out.println(str);

    输出结果:
    GET
    /index.html
    HTTP/1.1
     
        在使用split的第一种重载形式时应注意,如果分割后的字符串最后有空串,将被忽略。如使用正则表达式\d来分割字符串a0b1c3456时,得到的数组的长度为3,而不是7。
    在split的第二种重载形式中有一个limit参数,要分三种情况讨论:
     
    1. 大于0: 如limit的值为n,那么将对正则表达式使用n-1次,下面的代码:

    String s = "a0b1c3456";
    String ss[] 
    = s.split("\\d"3);
    for(String str: ss)
        System.out.println(str);


    输出结果:
     
    a
    b
    c3456
     
    从输出结果可以看出,程序只对" a0b1c3456"使用了两次正则表达式,也就是在少扫描完字符'1'后,不管后面有没有满足条件的字符串,都将后面的字符串作为一个整体来作为返回数组的最后一个值。
     
    2. 小于0: 不忽略结尾的空串。也就是上面的例子返回数组的长度应该是7,而不是3。
    3. 等于0:这是默认值,相当于split的第一种重载形式。
     
     
    三、replaceAll 和 replaceFirst方法
     
    为两个方法的定义如下:
    public String replaceAll(String regex, String replacement)
    public String replaceFirst(String regex, String replacement)
     
        这两个方法用replacement替换当前字符串中和regex匹配的字符串。使用方法很简单,这里不再详述,感兴趣的读者可以参考相关的文档。
     
    对于Java中正则表达式的详细内容,请参考JDK文档。
    posted @ 2008-11-11 14:56 jiafang83 阅读(185) | 评论 (0)编辑 收藏

    摘自:http://blog.csdn.net/zbzgigi/archive/2006/05/30/763795.aspx
    1、“.”为通配符,表示任何一个字符,例如:“a.c”可以匹配“anc”、“abc”、“acc”;
    2、“[]”,在[]内可以指定要求匹配的字符,例如:“a[nbc]c”可以匹配“anc”、“abc”、“acc”;但不可以匹配“ancc”,a到z可以写成[a-z],0到9可以写成[0-9];

    3、数量限定符号,表示匹配次数(或者叫做长度)的符号:

    包括:“*”——0次或者多次
          “+”——1次或者多次
          “?”——0次或者1次
          “{n}”——匹配n次,n为整数
          “{n,m}”——匹配从n到m之间的某个数的次数;n和m都是整数;
          “{n,}”——匹配n到无穷次之间任意次数;
          “{,m}”——匹配0到m之间任意次数;
    他们放到匹配格式的后面:
    例如:
    电话号码:024-84820482,02484820482(假设前面3或者4位,后面7或者8位,并且中间的减号可有可无)

    都是符合规定的,那么可以用如下格式来匹配:[0-9]{3,4} \-? [0-9]{7,8};
    注意:“\”为转义字符,因为“-”在正则表达式用有代表一个范围的意义,例如:前面所说的[0-9],

    所以它需要转义字符“\”进行转义才可使用;
    4、“^”为否符号,表示不想匹配的符号,例如:[^z][a-z]+可以匹配所有除“z”开头的以外的所有字

    符串(长度大于2,因为“+”表示大于等于1的次数,从第二位开始都是小写英文字符);
    如果^放到[]的外边则表示以[]开头的字符串;^[az][a-z]+表示a或者z开头的长度大于等于2的英文字符

    串;
    5、“|”或运算符,例如:a[n|bc|cb]c可以匹配“abcc”,“anc”,“acbc”;
    6、“$”以它前面的字符结尾的;例如:ab+$就可以被“abb”,“ab”匹配;
    7、一些简单表示方法:
    \d表示[0-9];\D表示[^0-9];\w表示[A-Z0-9];\W表示[^A-Z0-9];\s表示[\t\n\r\f],就是空格字符包括tab

    ,空格等等;\S表示[^\t\n\r\f],就是非空格字符;
    8、常用的匹配:
    匹配中文字符: “[\u4e00-\u9fa5]”;
    匹配双字节字符(包括汉字在内):“[^\x00-\xff]”;
    匹配空行的正则表达式:“\n[\s| ]*\r”;
    匹配HTML标记的正则表达式:“/<(.*)>.*<\/\1>|<(.*) \/>/”;
    匹配首尾空格的正则表达式:“(^\s*)|(\s*$)”;
    匹配非负整数(正整数 + 0):“^\d+$”;  
    匹配正整数:“^[0-9]*[1-9][0-9]*$”;
    匹配非正整数(负整数 + 0):“^((-\d+)|(0+))$”;
    匹配负整数:“^-[0-9]*[1-9][0-9]*$”;
    匹配整数:“^-?\d+$”;
    匹配非负浮点数(正浮点数 + 0):“^\d+(\.\d+)?$”
    匹配正浮点数:“^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*

    ))$”;
    ^((-\d+(\.\d+)?)|(0+(\.0+)?))$  //匹配非正浮点数(负浮点数 + 0)
    ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$  //匹配

    负浮点数
    匹配浮点数:“^(-?\d+)(\.\d+)?$”;
    匹配由数字、26个英文字母或者下划线组成的字符串:“^\w+$”;
    匹配email地址:“^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$”;
    匹配url:“^[a-zA-z]+://匹配(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$”

    下面是正则表达式中的一些常用模式。

    /pattern/  结果 
    . 匹配除换行符以外的所有字符
    x? 匹配 0 次或一次 x 字符串
    x* 匹配 0 次或多次 x 字符串,但匹配可能的最少次数
    x+ 匹配 1 次或多次 x 字符串,但匹配可能的最少次数
    .* 匹配 0 次或一次的任何字符
    .+ 匹配 1 次或多次的任何字符
    {m} 匹配刚好是 m 个 的指定字符串
    {m,n} 匹配在 m个 以上 n个 以下 的指定字符串
    {m,} 匹配 m个 以上 的指定字符串
    [] 匹配符合 [] 内的字符
    [^] 匹配不符合 [] 内的字符
    [0-9] 匹配所有数字字符
    [a-z] 匹配所有小写字母字符
    [^0-9] 匹配所有非数字字符
    [^a-z] 匹配所有非小写字母字符
    ^ 匹配字符开头的字符
    $ 匹配字符结尾的字符
    \d 匹配一个数字的字符,和 [0-9] 语法一样
    \d+ 匹配多个数字字符串,和 [0-9]+ 语法一样
    \D 非数字,其他同 \d
    \D+ 非数字,其他同 \d+
    \w 英文字母或数字的字符串,和 [a-zA-Z0-9] 语法一样
    \w+ 和 [a-zA-Z0-9]+ 语法一样
    \W 非英文字母或数字的字符串,和 [^a-zA-Z0-9] 语法一样
    \W+ 和 [^a-zA-Z0-9]+ 语法一样
    \s 空格,和 [\n\t\r\f] 语法一样
    \s+ 和 [\n\t\r\f]+ 一样
    \S 非空格,和 [^\n\t\r\f] 语法一样
    \S+ 和 [^\n\t\r\f]+ 语法一样
    \b 匹配以英文字母,数字为边界的字符串
    \B 匹配不以英文字母,数值为边界的字符串
    a|b|c 匹配符合a字符 或是b字符 或是c字符 的字符串
    abc 匹配含有 abc 的字符串
    (pattern) () 这个符号会记住所找寻到的字符串,是一个很实用的语法。第一个 () 内所找到的字符串
    变成 $1 这个变量或是 \1 变量,第二个 () 内所找到的字符串变成 $2 这个变量或是 \2 变量,以此
    类推下去。 
    /pattern/i i 这个参数表示忽略英文大小写,也就是在匹配字符串的时候,不考虑英文的大小写问题。
    \ 如果要在 pattern 模式中找寻一个特殊字符,如 "*",则要在这个字符前加上 \ 符号,这样才会让特殊
    字符失效
    3、正则表达式的八大原则
      如果在 Unix 中曾经使用过 sed、awk、grep 这些命令的话,相信对于正则表达式(Regular Expression)
    不会感到陌生。下面给大家介绍几条正则表达式使用过程中的 8 大原则。

    正则表达式在对付数据的战斗中可形成庞大的联盟——这常常是一场战争。我们要记住下面八条原则:

    · 原则1:正则表达式有三种不同形式(匹配(m/ /),替换(s/ / /eg)和转换(tr/ / /))。

    · 原则2:正则表达式仅对标量进行匹配( $scalar =~ m/a/; 可以工作; @array =~ m/a/ 将把@array作为标量
    对待,因此可能不会成功)。

    · 原则3:正则表达式匹配一个给定模式的最早的可能匹配。缺省时,仅匹配或替换正则表达式
    一次( $a = 'string string2'; $a =~ s/string/ /; 导致 $a = 'string 2')。

    · 原则4:正则表达式能够处理双引号所能处理的任意和全部字符( $a =~ m/$varb/ 在匹配前把varb扩展为
    变量;如果 $varb = 'a' $a = 'as',$a =~ s/$varb/ /; 等价于 $a =~ s/a/ /; ,执行结果使 $a = " s" )。

    · 原则5:正则表达式在求值过程中产生两种情况:结果状态和反向引用: $a=~ m/pattern/ 表示 $a 中是否有
    子串 pattern 出现,$a =~ s/(word1)(word2)/$2$1/ 则“调换”这两个单词。

    · 原则6:正则表达式的核心能力在于通配符和多重匹配运算符以及它们如何操作。$a =~ m/\w+/ 匹配一个或多个
    单词字符;$a =~ m/\d/" 匹配零个或多个数字。

    · 原则7:如果欲匹配不止一个字符集合,Perl使用 "|" 来增加灵活性。如果输入 m/(cat|dog)/ 则相当于“匹配
    字符串 cat 或者 dog。

    · 原则8:Perl用 (?..) 语法给正则表达式提供扩展功能。

    posted @ 2008-11-11 14:53 jiafang83 阅读(204) | 评论 (0)编辑 收藏

    log4j是一个很好的开源的日志项目,下面就我在实际中使用的一些情况作一个小结(我所写的是以spring为框架的运用,之所以要提到这点,是因为在spring中专门有处理log4j的地方,而我也用到了这些地方)。

      在使用的第一步你要明白你所发布的web项目所使用的服务器,因为不同的服务器对于使用log4j是有些不同的,我在实际使用中主要是用tomcat和 jboss两类,对于tomcat,它本身是没有配置log4j的,所以使用起来和常规的一样;而在jboss中它是本身配置了log4j的,所以有时候 我们在看项目代码时,其整个项目并没有log4j的配置文件,而在一些类中仍然定义了Logger,例如static Logger log = org.apache.log4j.Logger.getLogger(UserDaoImple.class);,这就表明开发者打算使用jboss默 认的log4j的配置,我们可以在jboss下的对应的log目录下的server.log中看到日志,jboss本身的log4j的配置是将 debug,info级的日志写在server.log中,而像error等级别比较高的日志打印到控制台上,而写到server.log中的日志比较 多,并不方便查看。于是我们想到使用自己的log4j配置写到某个具体的文件中(注意文件要先建立,才能忘里面写东西,log4j自己不能建立文件),但 这里因为jboss有它自己的log4j配置,所以如果我们配置的log4j包含Console的Appender时,就会出错,错误类似于

    ERROR: invalid console appender config detected, console stream is looping.
    解决方法一是不用Console的Appender,或者改jboss的配置文件,在jboss-service.xml文件里,把
    <mbean code="org.jboss.logging.Log4jService" name="jboss.system:type=Log4jService,service=Logging">
            <attribute name="ConfigurationURL">resource:log4j.xml</attribute>
            <attribute name="CatchSystemOut">false</attribute>
            <attribute name="Log4jQuietMode">true</attribute>
    </mbean>。

    我建议不用Console的Appender,当然这是对jboss3.2.x是这样,对于jboss4.0.x如果我们要用自己的log4j配置照上述改还是会有问题,会有类似于log4j:ERROR A "org.jboss.logging.util.OnlyOnceErrorHandler" object is not assignable to a "org.apache.log4j.spi.ErrorHandler" variable的异常,解决方法是把/server/default/jbossweb-tomcat55.sar/META-INF/jboss-service.xml 中的以下两个熟悉改成true
    <attribute name="Java2ClassLoadingCompliance">true</attribute>
    <attribute name="UseJBossWebLoader">true</attribute>

    以上就是使用jboss服务器可能出现的问题,解决了这些再来使用log4j就比较简单了。

    下面说说对于采用了spring框架的项目如何使用log4j,在spring中使用log4j,有些方便的地方,

    1. 动态的改变记录级别和策略,即修改log4j.properties,不需要重启Web应用,这需要在web.xml中设置一下。
    2. 把log文件定在 /WEB-INF/logs/ 而不需要写绝对路径。
    3. 可以把log4j.properties和其他properties一起放在/WEB-INF/ ,而不是Class-Path。

    首先我们在web.xml中需要设定一下

    <context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>WEB-INF/log4j.properties</param-value>
    </context-param>

    <context-param>
    <param-name>log4jRefreshInterval</param-name>
    <param-value>60000</param-value>
    </context-param>

    <listener>
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener> 
    其中第二部分就是能够动态修改log4j.properties的关键,容器会每60秒扫描log4j的配置文件 。
    对 于log4j的配置文件如何写,这就不多说了,大家可以去google,有一点就是我们如果用RollingFileAppender或者 FileAppender时,可以通过${webapp.root}来定位到服务器的发布的该项目下,这是spring把web目录的路径压入到了 webapp.root的系统变量。然后,在log4j.properties 里就可以这样定义logfile位置
    log4j.appender.logfile.File=${webapp.root}/WEB-INF/logs/myfuse.log
    如果有多个web应用,怕webapp.root变量重复,可以在context-param里定义webAppRootKey。

    当我们定义完log4j.properties后,剩下的就是在需要记录的class中new 出Logger了 

    常用log4j配置

    常用log4j配置,一般可以采用两种方式,.properties和.xml,下面举两个简单的例子:
    一、log4j.properties
    ### 设置org.zblog域对应的级别INFO,DEBUG,WARN,ERROR和输出地A1,A2 ##
    log4j.category.org.zblog=ERROR,A1
    log4j.category.org.zblog=INFO,A2
    log4j.appender.A1=org.apache.log4j.ConsoleAppender
    ### 设置输出地A1,为ConsoleAppender(控制台) ##
    log4j.appender.A1.layout=org.apache.log4j.PatternLayout
    ### 设置A1的输出布局格式PatterLayout,(可以灵活地指定布局模式)##
    log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n
    ### 配置日志输出的格式##
    log4j.appender.A2=org.apache.log4j.RollingFileAppender
    ### 设置输出地A2到文件(文件大小到达指定尺寸的时候产生一个新的文件)##
    log4j.appender.A2.File=E:/study/log4j/zhuwei.html
    ### 文件位置##
    log4j.appender.A2.MaxFileSize=500KB
    ### 文件大小##
    log4j.appender.A2.MaxBackupIndex=1
    log4j.appender.A2.layout=org.apache.log4j.HTMLLayout
    ##指定采用html方式输出
    二、log4j.xml
    <?xml version="1.0" encoding="GB2312" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="org.zblog.all" class="org.apache.log4j.RollingFileAppender">
    <!-- 设置通道ID:org.zblog.all和输出方式:org.apache.log4j.RollingFileAppender -->
       <param name="File" value="E:/study/log4j/all.output.log" /><!-- 设置File参数:日志输出文件名 -->
       <param name="Append" value="false" /><!-- 设置是否在重新启动服务时,在原有日志的基础添加新日志 -->
       <param name="MaxBackupIndex" value="10" />
       <layout class="org.apache.log4j.PatternLayout">
           <param name="ConversionPattern" value="%p (%c:%L)- %m%n" /><!-- 设置输出文件项目和格式 -->
       </layout>
    </appender>
    <appender name="org.zblog.zcw" class="org.apache.log4j.RollingFileAppender">
       <param name="File" value="E:/study/log4j/zhuwei.output.log" />
       <param name="Append" value="true" />
       <param name="MaxFileSize" value="10240" /> <!-- 设置文件大小 -->
       <param name="MaxBackupIndex" value="10" />
       <layout class="org.apache.log4j.PatternLayout">
           <param name="ConversionPattern" value="%p (%c:%L)- %m%n" />
       </layout>
    </appender>
    <logger name="zcw.log"> <!-- 设置域名限制,即zcw.log域及以下的日志均输出到下面对应的通道中 -->
       <level value="debug" /><!-- 设置级别 -->
       <appender-ref ref="org.zblog.zcw" /><!-- 与前面的通道id相对应 -->
    </logger>
    <root> <!-- 设置接收所有输出的通道 -->
       <appender-ref ref="org.zblog.all" /><!-- 与前面的通道id相对应 -->
    </root>
    </log4j:configuration>
    三、配置文件加载方法:
    import org.apache.log4j.Logger;
    import org.apache.log4j.PropertyConfigurator;
    import org.apache.log4j.xml.DOMConfigurator;
    public class Log4jApp {
       public static void main(String[] args) {
           DOMConfigurator.configure("E:/study/log4j/log4j.xml");//加载.xml文件
           //PropertyConfigurator.configure("E:/study/log4j/log4j.properties");//加载.properties文件
           Logger log=Logger.getLogger("org.zblog.test");
           log.info("测试");
       }
    }
    四、项目使用log4j
    在web 应用中,可以将配置文件的加载放在一个单独的servlet中,并在web.xml中配置该servlet在应用启动时候加载。对于在多人项目中,可以给每一个人设置一个输出通道,这样在每个人在构建Logger时,用自己的域名称,让调试信息输出到自己的log文件中。
    五、常用输出格式
    # -X号:X信息输出时左对齐;
    # %p:日志信息级别
    # %d{}:日志信息产生时间
    # %c:日志信息所在地(类名)
    # %m:产生的日志具体信息
    # %n:输出日志信息换行

    Log4J 最佳实践之全能配置文件

    给出得Log4J配置文件实现了输出到控制台,文件,回滚文件,发送日志邮件,输出到数据库日志表,自定义标签等全套功能。

    log4j.rootLogger=DEBUG,CONSOLE,A1,im
    #DEBUG,CONSOLE,FILE,ROLLING_FILE,MAIL,DATABASE

    log4j.addivity.org.apache=true


    ###################
    # Console Appender
    ###################
    log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
    log4j.appender.Threshold=DEBUG
    log4j.appender.CONSOLE.Target=System.out
    log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
    log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
    #log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n


    #####################
    # File Appender
    #####################
    log4j.appender.FILE=org.apache.log4j.FileAppender
    log4j.appender.FILE.File=file.log
    log4j.appender.FILE.Append=false
    log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
    log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
    # Use this layout for LogFactor 5 analysis



    ########################
    # Rolling File
    ########################
    log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
    log4j.appender.ROLLING_FILE.Threshold=ERROR
    log4j.appender.ROLLING_FILE.File=rolling.log
    log4j.appender.ROLLING_FILE.Append=true
    log4j.appender.ROLLING_FILE.MaxFileSize=10KB
    log4j.appender.ROLLING_FILE.MaxBackupIndex=1
    log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
    log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n


    ####################
    # Socket Appender
    ####################
    log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender
    log4j.appender.SOCKET.RemoteHost=localhost
    log4j.appender.SOCKET.Port=5001
    log4j.appender.SOCKET.LocationInfo=true
    # Set up for Log Facter 5
    log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout
    log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n


    ########################
    # Log Factor 5 Appender
    ########################
    log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
    log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000


    ########################
    # SMTP Appender
    #######################
    log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
    log4j.appender.MAIL.Threshold=FATAL
    log4j.appender.MAIL.BufferSize=10
    log4j.appender.MAIL.From=chenyl@hollycrm.com
    log4j.appender.MAIL.SMTPHost=mail.hollycrm.com
    log4j.appender.MAIL.Subject=Log4J Message
    log4j.appender.MAIL.To=chenyl@hollycrm.com
    log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
    log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n


    ########################
    # JDBC Appender
    #######################
    log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender
    log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test
    log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver
    log4j.appender.DATABASE.user=root
    log4j.appender.DATABASE.password=
    log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')
    log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout
    log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n


    log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.A1.File=SampleMessages.log4j
    log4j.appender.A1.DatePattern=yyyyMMdd-HH'.log4j'
    log4j.appender.A1.layout=org.apache.log4j.xml.XMLLayout

    ###################
    #自定义Appender
    ###################
    log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender

    log4j.appender.im.host = mail.cybercorlin.net
    log4j.appender.im.username = username
    log4j.appender.im.password = password
    log4j.appender.im.recipient = corlin@cybercorlin.net

    log4j.appender.im.layout=org.apache.log4j.PatternLayout
    log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

    posted @ 2008-11-10 15:45 jiafang83 阅读(17029) | 评论 (2)编辑 收藏

    转载:http://hi.baidu.com/fgfd0/blog/item/fa547ff01ffc7faaa50f522e.html
    log4j与log4j.properties的配置说明
    在强调可重用组件开发的今天,除了自己从头到尾开发一个可重用的日志***作类外,Apache为我们提供了一个强有力的日志***作包-Log4j。

    Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

    此外,通过Log4j其他语言接口,您可以在C、C++、.Net、PL/SQL程序中使用Log4j,其语法和用法与在Java程序中一样,使得多语言分布式系统得到一个统一一致的日志组件模块。而且,通过使用各种第三方扩展,您可以很方便地将Log4j集成到J2EE、JINI甚至是SNMP应用中。

    说明:下面分为三部分,第一部分讲解如何配置log4j,第二部分为对log4j.properties配置文件中的各个属性的讲解,第三部分为对log4j的详细讲解,如果只想配置上log4j,那么只需要看前两个部分就可以,如果想对log4j深入了解,则还需看第三部分。

    一、Log4j配置

    第一步:加入log4j-1.2.8.jar到lib下。

    第二步:在CLASSPATH下建立log4j.properties。内容如下:

    1 log4j.rootCategory=INFO, stdout , R

    2

    3 log4j.appender.stdout=org.apache.log4j.ConsoleAppender

    4 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

    5 log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n

    6

    7 log4j.appender.R=org.apache.log4j.DailyRollingFileAppender

    8 log4j.appender.R.File=D:\Tomcat 5.5\logs\qc.log

    9 log4j.appender.R.layout=org.apache.log4j.PatternLayout

    10 log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n

    11

    12 log4j.logger.com.neusoft=DEBUG

    13 log4j.logger.com.opensymphony.oscache=ERROR

    14 log4j.logger.net.sf.navigator=ERROR

    15 log4j.logger.org.apache.commons=ERROR

    16 log4j.logger.org.apache.struts=WARN

    17 log4j.logger.org.displaytag=ERROR

    18 log4j.logger.org.springframework=DEBUG

    19 log4j.logger.com.ibatis.db=WARN

    20 log4j.logger.org.apache.velocity=FATAL

    21

    22 log4j.logger.com.canoo.webtest=WARN

    23

    24 log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN

    25 log4j.logger.org.hibernate=DEBUG

    26 log4j.logger.org.logicalcobwebs=WARN

    第三步:相应的修改其中属性,修改之前就必须知道这些都是干什么的,在第二部分讲解。

    第四步:在要输出日志的类中加入相关语句:

    定义属性:protected final Log log = LogFactory.getLog(getClass());

    在相应的方法中:

    if (log.isDebugEnabled())

    {

    log.debug(“System …..”);

    }

    二、Log4j说明

    1 log4j.rootCategory=INFO, stdout , R

    此句为将等级为INFO的日志信息输出到stdout和R这两个目的地,stdout和R的定义在下面的代码,可以任意起名。等级可分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL,如果配置OFF则不打出任何信息,如果配置为INFO这样只显示INFO, WARN, ERROR的log信息,而DEBUG信息不会被显示,具体讲解可参照第三部分定义配置文件中的logger。

    3 log4j.appender.stdout=org.apache.log4j.ConsoleAppender

    此句为定义名为stdout的输出端是哪种类型,可以是

    org.apache.log4j.ConsoleAppender(控制台),

    org.apache.log4j.FileAppender(文件),

    org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),

    org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)

    org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

    具体讲解可参照第三部分定义配置文件中的Appender。

    4 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

    此句为定义名为stdout的输出端的layout是哪种类型,可以是

    org.apache.log4j.HTMLLayout(以HTML表格形式布局),

    org.apache.log4j.PatternLayout(可以灵活地指定布局模式),

    org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),

    org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

    具体讲解可参照第三部分定义配置文件中的Layout。

    5 log4j.appender.stdout.layout.ConversionPattern= [QC] %p [%t] %C.%M(%L) | %m%n

    如果使用pattern布局就要指定的打印信息的具体格式ConversionPattern,打印参数如下:

    %m 输出代码中指定的消息

    %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL

    %r 输出自应用启动到输出该log信息耗费的毫秒数

    %c 输出所属的类目,通常就是所在类的全名

    %t 输出产生该日志事件的线程名

    %n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”

    %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921

    %l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。

    [QC]是log信息的开头,可以为任意字符,一般为项目简称。

    输出的信息

    [TS] DEBUG [main] AbstractBeanFactory.getBean(189) | Returning cached instance of singleton bean 'MyAutoProxy'

    具体讲解可参照第三部分定义配置文件中的格式化日志信息。

    7 log4j.appender.R=org.apache.log4j.DailyRollingFileAppender

    此句与第3行一样。定义名为R的输出端的类型为每天产生一个日志文件。

    8 log4j.appender.R.File=D:\Tomcat 5.5\logs\qc.log

    此句为定义名为R的输出端的文件名为D:\Tomcat 5.5\logs\qc.log

    可以自行修改。

    9 log4j.appender.R.layout=org.apache.log4j.PatternLayout

    与第4行相同。

    10 log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n

    与第5行相同。

    12 log4j.logger.com. neusoft =DEBUG

    指定com.neusoft包下的所有类的等级为DEBUG。

    可以把com.neusoft改为自己项目所用的包名。

    13 log4j.logger.com.opensymphony.oscache=ERROR

    14 log4j.logger.net.sf.navigator=ERROR

    这两句是把这两个包下出现的错误的等级设为ERROR,如果项目中没有配置EHCache,则不需要这两句。

    15 log4j.logger.org.apache.commons=ERROR

    16 log4j.logger.org.apache.struts=WARN

    这两句是struts的包。

    17 log4j.logger.org.displaytag=ERROR

    这句是displaytag的包。(QC问题列表页面所用)

    18 log4j.logger.org.springframework=DEBUG

    此句为Spring的包。

    24 log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN

    25 log4j.logger.org.hibernate=DEBUG

    此两句是hibernate的包。

    以上这些包的设置可根据项目的实际情况而自行定制。

    三、log4j详解

    1、定义配置文件

    Log4j支持两种配置文件格式,一种是XML格式的文件,一种是Java特性文件log4j.properties(键=值)。下面将介绍使用log4j.properties文件作为配置文件的方法:

    ①、配置根Logger

    Logger 负责处理日志记录的大部分***作。

    其语法为:

    log4j.rootLogger = [ level ] , appenderName, appenderName, …

    其中,level 是日志记录的优先级,分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者自定义的级别。Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定义了INFO级别,只有等于及高于这个级别的才进行处理,则应用程序中所有DEBUG级别的日志信息将不被打印出来。ALL:打印所有的日志,OFF:关闭所有的日志输出。 appenderName就是指定日志信息输出到哪个地方。可同时指定多个输出目的地。

    ②、配置日志信息输出目的地 Appender

    Appender 负责控制日志记录***作的输出。

    其语法为:

    log4j.appender.appenderName = fully.qualified.name.of.appender.class

    log4j.appender.appenderName.option1 = value1

    log4j.appender.appenderName.optionN = valueN

    这里的appenderName为在①里定义的,可任意起名。

    其中,Log4j提供的appender有以下几种:

    org.apache.log4j.ConsoleAppender(控制台),

    org.apache.log4j.FileAppender(文件),

    org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),

    org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件),可通过log4j.appender.R.MaxFileSize=100KB设置文件大小,还可通过log4j.appender.R.MaxBackupIndex=1设置为保存一个备份文件。

    org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

    例如:log4j.appender.stdout=org.apache.log4j.ConsoleAppender

    定义一个名为stdout的输出目的地,ConsoleAppender为控制台。

    ③、配置日志信息的格式(布局)Layout

    Layout 负责格式化Appender的输出。

    其语法为:

    log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class

    log4j.appender.appenderName.layout.option1 = value1

    log4j.appender.appenderName.layout.optionN = valueN

    其中,Log4j提供的layout有以下几种:

    org.apache.log4j.HTMLLayout(以HTML表格形式布局),

    org.apache.log4j.PatternLayout(可以灵活地指定布局模式),

    org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),

    org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

    2、格式化日志信息

    Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下:

    %m 输出代码中指定的消息

    %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL

    %r 输出自应用启动到输出该log信息耗费的毫秒数

    %c 输出所属的类目,通常就是所在类的全名

    %t 输出产生该日志事件的线程名

    %n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”

    %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921

    %l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。

    3、在代码中使用Log4j

    我们在需要输出日志信息的类中做如下的三个工作:

    1、导入所有需的commongs-logging类:

    import org.apache.commons.logging.Log;

    import org.apache.commons.logging.LogFactory;

    2、在自己的类中定义一个org.apache.commons.logging.Log类的私有静态类成员:

    private final Log log = LogFactory.getLog(getClass());

    LogFactory.getLog()方法的参数使用的是当前类的class。

    3、使用org.apache.commons.logging.Log类的成员方法输出日志信息:

    if (log.isDebugEnabled())

    {

    log.debug("111");

    }

    if (log.isInfoEnabled())

    {

    log.info("222");

    }

    if (log.isWarnEnabled())

    {

    log.warn("333");

    }

    if (log.isErrorEnabled())

    {

    log.error("444");

    }

    if (log.isFatalEnabled())

    {

    log.fatal("555")

    }

    posted @ 2008-11-10 15:43 jiafang83 阅读(143) | 评论 (0)编辑 收藏
    关于JSP页面中的pageEncoding和contentType两种属性的区别:

      pageEncoding是jsp文件本身的编码

      contentType的charset是指服务器发送给客户端时的内容编码

      JSP要经过两次的“编码”,第一阶段会用pageEncoding,第二阶段会用utf-8至utf-8,第三阶段就是由Tomcat出来的网页, 用的是contentType。

      第一阶段是jsp编译成.java,它会根据pageEncoding的设定读取jsp,结果是由指定的编码方案翻译成统一的UTF-8 JAVA源码(即.java),如果pageEncoding设定错了,或没有设定,出来的就是中文乱码。

      第二阶段是由JAVAC的JAVA源码至java byteCode的编译,不论JSP编写时候用的是什么编码方案,经过这个阶段的结果全部是UTF-8的encoding的java源码。

      JAVAC用UTF-8的encoding读取java源码,编译成UTF-8 encoding的二进制码(即.class),这是JVM对常数字串在二进制码(java encoding)内表达的规范。

      第三阶段是Tomcat(或其的application container)载入和执行阶段二的来的JAVA二进制码,输出的结果,也就是在客户端见到的,这时隐藏在阶段一和阶段二的参数contentType就发挥了功效

      contentType的設定.

      pageEncoding 和contentType的预设都是 ISO8859-1. 而随便设定了其中一个, 另一个就跟着一样了(TOMCAT4.1.27是如此). 但这不是绝对的, 这要看各自JSPC的处理方式. 而pageEncoding不等于contentType, 更有利亚洲区的文字 CJKV系JSP网页的开发和展示, (例pageEncoding=GB2312 不等于 contentType=utf-8)。

      jsp文件不像.java,.java在被编译器读入的时候默认采用的是操作系统所设定的locale所对应的编码,比如中国大陆就是GBK,台湾就是BIG5或者MS950。而一般我们不管是在记事本还是在ue中写代码,如果没有经过特别转码的话,写出来的都是本地编码格式的内容。所以编译器采用的方法刚好可以让虚拟机得到正确的资料。

      但是jsp文件不是这样,它没有这个默认转码过程,但是指定了pageEncoding就可以实现正确转码了。

      举个例子:

    <%@ page contentType="text/html;charset=utf-8" %>

      大都会打印出乱码,因为输入的“你好”是gbk的,但是服务器是否正确抓到“你好”不得而知。

      但是如果更改为

    <%@ page contentType="text/html;charset=utf-8" pageEncoding="GBK"%>

      这样就服务器一定会是正确抓到“你好”了。

    posted @ 2008-11-07 17:42 jiafang83 阅读(1200) | 评论 (1)编辑 收藏

    执行某jsp页面时,弹出如标题所示异常,jsp代码如下:

    <%@ page language="java" contentType="text/html;charset=gbk" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
    <%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
      </head>
     
      <body>
        This is the result:
        <c:out value="${userInfo}" default="没有结果"/>
      </body>
    </html>


    异常的原因是不能识别“${userInfo}”,解决办法有两种:
    一、在page指令里,加入isELIgnored="true"属性,即
    <%@ page language="java" contentType="text/html;charset=gbk"  isELIgnored="true" %>
    二、把<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>变为:
    <%@ taglib prefix="c" uri=http://java.sun.com/jstl/core_rt  %>
    经过改动之后,jsp页面能正常执行了。
    posted @ 2008-11-07 16:48 jiafang83 阅读(27829) | 评论 (7)编辑 收藏