随笔-54  评论-0  文章-2  trackbacks-0
 

   今天是jBPM的第二天,内容不多,定义不少,主要讲了流程变量,节点和事件等知识,全是新的知识,刚学肯定生疏,久了就没问题了,编程嘛,多敲代码,多 调试,才是王道。
 
1. 流程变量

通过org.jbpm.context.exe.ContextInstance来操 作变量。

2.变量的生命周期

变量的访问和赋值是在某一个token上进行的,缺省时,是基于root Token。每个Token(执行路线)有它自己的一套流程变量。变量的作用域和所属的Token的生命周期一致,不同的Token上的同名变量互不影 响。
 
3.变量值要求

变量名的类型为java.lang.String,支持的变量值类型如下(文档10.1节)。(

如 果变量值是classes that are persistable with hibernate,则POJO的id应为long型或String型。
 
saveOrUpdate( po );
savePoIdAndPoClassAsVariable()
session.get( class, id )
节点

1. 流程图中的各种节点的作用及用法

为什么需要多种节点类型?

需要有不同类型(作用)的节点,才能设计出复杂的流程图。 Jbpm有一套预先定义好的节点类型。如果不够用,也可以使用自定义节点进行扩展,以完成不同的流程的需要。

不同的节点类型代表不同的行 为。

每个流程都必须要有开始节点和结束节点。

2.预定义节点

start-state,开始节点:标识流 程开始、
end-state,结束节点:标识流程结束、
task-node,任务节点:可以放0个或多个任务、
decision, 决策节点:路径选择,只使用一个流转(叉路口)、
fork/join,分支节点/合并节点:可以分为多个并行执行的分支、
state,状 态节点:等待。


每个节点都对应一个类(Jbpm的持久化类),都是org.jbpm.graph.def.Node的子类。节点 都有名字、流转(end-state除外)。

event事件

事 件。

1, 有几种事件,分别在什么时候触发
2, 怎么指定当事件触发时做什么事(Action)
 1, 节点的事件

a)      进入节点(node-enter)。(开始节点没有)

b)      离开节点(node-leave)。(结束节点没有)

2, 流转的事件

a)      只有一个:使用流转(take a transition)

3, 任务的事件

a)      创建任务(task-create)

b)      分配任务(task-assign)

c)      开始任务(task-start)à TaskInstance.start()

d)      结束任务(task-end)à TaskInstance.end()
 每个事件有一个动作(action)清单。当jBPM引擎产生一个事件,动作(action)清单就会被 执行. 不同的节点支持的事件类型不同,是由event元素所在的节点的类型决定的,例如transition只有一个事件。
可以在event元 素用可以指定一个动作,当指定的事件发生时,这个动作被执行。

可以给同一个事件指定多个动作,当这个事件触发的时候,这些动作执行的顺序 和定义先后顺序是一致的。

不同元素支持不同的事件类型:

一般的节点都具有的事件:node-enter,进入节点、 node-leave,离开节点;
start-state只有node-leave;
end-state只有node-enter;
transition 只有一个执行转换的事件(taking a transition)。因为只有一个事件,所以配置时不用写event元素,而直接配置Action。
task 有task-create,任务创建、task-assign,任务分配、task-start,任务开始、task-end,任务结束。

关 于哪些元素支持哪些事件,可以通过文档的18.4节中的xml文件的写法中获得。

如果配置的事件类型不存在,不会报错,也不会执行。

注 意:在事件中定义的动作(Action)不应该(不能)影响流程的执行。即不要在事件的动作中给token发信号,否则会抛异常:token is locked。(在Node中配置的Action可以给Token发信号。)

事件执行的顺序:

已触发事件:node-leave

已触发事件:transition

已 触发事件:node-enter

已触发事件:task-create

已触发事件:task-assign

已 触发事件:task-start

已触发事件:task-end
 

************************* 动态的创建不确定数量的任务实例 *********

会签。

实现任务分配给多个人,在流程定义中定义的相 应的任务,不指定参与者,也不知道指定为谁。需要做以下工作:
1,  阻止jBPM自动创建任务实例(设置task-node的create-tasks="false")
2,  在node-enter事件中定义一个动作指定用于创建TaskInstance的类。

类 CreateTaskInstancesAction要接管两个操作:创建与分配任务实例。
 创建任务实例要调用方法:

  TaskMgmtInstance.createTaskInstance(Task, ExecutionContext);

其中的 Task 是任务的定义,可以先得到当前的节点:

  TaskNode taskNode = (TaskNode) executionContext.getNode();

然后通过任务的名字得到任务的定义:

  Task task = taskNode.getTask("审批");

 

任务分配

个人任务:actor-id=”xxx”
                   

查询组任务列表的方法为:

TaskMgmtSession.findPooledTaskInstances(String actorId)
                      

对于一个组任务,如果他的actorId为null,组中所 有的用户都可以在组任务列表中看到这个任务。如果使用TaskInstance.setActorId(String)方法设置这个任务由指定的 acrorId来办理,这时pooledActors中的其他人就看不到这个任务了,就是说actorId会屏蔽pooledActors; 当这个用户因某些原因不能办理任务时,可以把这个任务再退回到组任务列表中,方法是调用TaskInstance.setActorId(null)设置 actorId为null,这时pooledActors中的所有人又都可以看到这个任务了。

不管使用哪种方式分配任务,参与者 (Actor-id,字符串类型)的计算(确定)都是由业务层负责解释的。

    最后汤兄给我们推荐了一些好书,学习java必须准备三样: 心态,基础,睡觉。能学多少学多少。明天才是OA工作流项目的开始!加油。。。
posted @ 2010-02-01 21:59 d66380022| 编辑 收藏
JBPMOA项目

   哈 哈,今天终于要开始做项目了,心情特别好,在第一天中汤兄让我们先明白了什么是工作流,怎样很好的解决这一类问题等,接着来了个Helloworld,就入门了。每天都在学习,每天都有收获,感觉真好。还要再提一下,OA(办公自动化)主要技术之一就是工作流,好,还是仔细总结一下一天所学:

 

1. 工作流就是工 作流程的计算机化

  流程(OA),数量多,随时更改

  网购:提交订单>配货>发货>收货>付款

当我们想增加、修改流程时,而不想编程则需要用到工作流引擎,由它负责判断下一步 做什么。下图是它的原理:

  状态机 +if else

 

2. 工作流要解决的主要问题是:为实现某个业务目 标,在多个参与者之间,利用计算机,按某种预定规则自 动传递文档、信息或者任务。

通俗的说,就是多个人在一起合作完成某件事情。

 

接下来是jBPM介绍

3.jBPM介绍

 jBPM全称是Java Business Process Management。是一种基于J2EE的轻量级工作流管理系统,jBPM是公开源 代码项目

官方主页http://labs.jboss.com/

下载地址:http://labs.jboss.com/jbossjbpm

 

最重要的还是接下来的jBPM的使用

 4.Jbpm的使用

server:提供的一个执行、测试工作流和平台(Web应用程序)。

 

流程图是一个有向图,由两部分组成:节点和流转。节点有各种各样形状(代表各种各 样的作用)。流转就是指单箭头,代表从一个节点到下一个节点。

 

此文件的约束就是 jPDL

jPDL中,不同 的节点,就用不同的标签。

 

1.xml文件名必须为:processdefinition.xml

2.必须要在一个zip文件的根目 录中。

3.可以有一个名为processimage.jpg的文件,是流程图。

 

应用myEclipse设 计流程图步骤:

 

1.jbpm-jpdl-3.2.2插件:

找到jbpm-jpdl-3.2.2下的designer路 径复制一下,注意路径中不能有中文

2.之后在桌面上myEclipse快 捷方式,点右键,查找目标,找到myEclipse安装目录,再其下的links目录下 加入a.link文件 (a可以随意写),内容为 path=粘贴  注意里路径变为双斜线,之后关闭myEclipse,再打开就OK了。

3.myEclipse下新建介绍java工程,在src下,新建Process Definition点下一步,为Process name :起个名,比如HelloWorld 。。。。

 

4启动服务器:server/start.bat

5访问http://localhost:8080/jbpm-console登陆后Deploy下图

 6.zip文件部署

       7.点Deploy

8.start

9.tokens 后点singal,后在其下点singal

10.tasks,点start ,按部就班搞定

 

注意事项:

 

1.怎么从开始节点往下走?Tokens à Signal(只点一次)

2.怎么没有properties窗口?Window à Show View à Properties

3.怎么一点Signal,就结束了呢?没有在Task-Node中 定义任务吧。要说明任务名称与任务的执行者。

4.点击Process Image,在图片上没有一个正在运 行的标志,而且在上方还有一个错误提示?把节点的名称改为英文,重新Deploy就可 以了。

Jboss Server所在的路径中不能有 中文或特殊 字符(如&,有的在文件夹jbpm&oa中,这样就不行),否则不能运行

 

Token的解释:流程实例通过Token的维护 当前正在执行的节点

入门程序:

HelloWorld

1, 设计流程定义à 打包为zip文件(流程 定义文档,说明par的格式要 求)

2, 部署流程定义à 把工作流交给工 作流管理系统保存起来。只需要执行一次,一般是管理员进行操作。

3, 执行流程à 多个操作:

a)      启动(创建)流程实例(Signal

b)      获取任务列表(只是自已的任务实 例列表)

c)      办理任务

                    i.        开始任务

                    ii.        结束任务

今天就这么多了,明天再写!

posted @ 2010-01-31 23:36 d66380022| 编辑 收藏
     今天继续讲的是lucene的分词器,汤兄先回顾了昨天的所学内容,很好。今天讲了lucene的细节,比如分词器和高亮器,以及高级搜索等功能的实现框架Compass,案例是传智的贴吧搜索功能的实现,用的当然也是lucene

 

                                      全文检索(Lucene)的深入

分词器:对文本资源进行切分,将文本按规则切 分为一个个可以进行索引的最小单位(关键词)。

某文档中的一段文本,经过分词后如下:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

Internet

采集

信息

软件

叫做

爬虫

蜘蛛

 

建立索引和进行搜索时都要用到分词器。为了保证能正确的搜索到结果,在建立索引 与进行搜索时使用的分词器应是同一个。

 

全文检索不区分大小写

对于中文分词,通常有三种方式:单字分词、二分法分词、词典分词。

最好的分词器:词库分词

  高亮器:

1.作用:

  1.截取摘要(大小)

  2.高亮关键字(前缀 后缀)

2.怎么用:

   过滤器 Filter

RangeFilter,可以对搜索出来的结果进行过 滤。

 排序 sort

Lucene的搜索结果默认按相关度排序的。所谓相关度,就是文档的得分。Lucene有一个评分机制,就是对检索结果按某种标准进行评估,然后按分值的高低来对结果进行排序。


查询对象

TermQuery

 Term是查询的最小单位,第一个参数是属性,第 二个是要查询的内容,下面的代码的

整个意思就是在title中查询检索

  Term term = new Term(“title”,”检索”);

  Query query = new TermQuery(term);

 

关键词查询RangeQuery

范围查询WildcardQueryPhraseQuery

短语查询

BooleanQuery

public void add(Query query, Occur occur)

 

Occur 用于表示布尔查询子句关系的类,包括:

Occur.MUSTOccur.MUST_NOTOccur.SHOULD

 

1,  MUSTMUST:取得连个查询子句的交集。

2,  MUSTMUST_NOT:包含MUST并且查询结果中不包含MUST_NOT的检索结果。

3,  SHOULDSHOULD,表示“或”关系,最终检索结果为所有检索子句的并集。


                                Compass框架

Lucene  + Hibernate

Hibernate操作实现原理:

主配置文件 hibernate.cfg.xml

            1.连接信息

                     2.声明映射文件

            3.其他配置

映射文件:.hbm.xml

          对象

                属性

同样,Compass实现原理如图:

posted @ 2010-01-31 23:35 d66380022| 编辑 收藏
 
           Lucene

今天由汤阳光老师(不如说是汤兄)给我们讲lucene,一见汤兄,太年轻了,真是这感觉真让我有些小惭愧,呵呵。。。还是学好技术是第一要务。

从 现在到年前都是汤兄给我们上课,今天和明天是搜索引擎,存储数据用的是Hibernate,全文检索的简化框架是Compass,Lucene讲1.5 天,Compass讲半天。总结一天所学的.全文检索是目前最流行的技术,由于用数据库搜索实现的匹配度,相关度排序和搜索速度太慢,而这些都非常致命。 下面详细回顾:

1.信息检索:找出与用户需求相关的信息

平时接触的信息有文:html,doc,pdf和 txt,

多媒体:音频,视频,图片...

全文检索:  1.只关注文本。比如我搜索:中国的首都在哪里?和我搜索中国 首都 北京是一样的,我们主要是研究出现了某些词的文本 2.不处理语义,只是词匹配

全文检索的作用:1.bbs,blog,news,商城的站内搜索,资源有限

Eclipse的帮助就是用Lucene做的

2.入门

运行原理/入门概念

Hello World

需求:就像百度的搜索框一样,输入内容,点击搜索,得出结果,并且要求时间非常短
后台:点搜索后,会去信息集合(索引库)里搜索,注:这个索引库是按照一定的结构存储,这个结构可以实现快速搜索
使用流程:1事先就不停再找,建立索引,2.搜索
索引库的结构:索引库是存到一些二进制文件,这些文件在同一个目录下  --à索引库目录
Document  一条数据
Field  数据中的一个字段

Field是组成Document的元素

实现:
步骤:1.建立索引

      2.搜索

      都用到的是分词器(analyzer),应使用同一种分词器

实现HelloWorld:添加jar包

lucene-core-2.4.0.jar(核心);
contrib/analyzers/lucene-analyzers-2.4.0.jar(分词器);
contrib/highlighter/lucene-highlighter-2.4.0.jar(高亮器);
  1.建立Article.java,属性有id,title,content
 2.HelloWorld.java.两个主要方法:
    1.建立索引:
     createIndex()    
    2.搜索
    search()
进行搜索
public void search() throws Exception {
    String queryString = "document";
    // 1,把要搜索的文本解析为 Query
    String[] fields = { "name", "content" };
   QueryParser queryParser = new MultiFieldQueryParser(fields, analyzer);
    Query query = queryParser.parse(queryString);
 
    // 2,进行查询
    IndexSearcher indexSearcher = new IndexSearcher(indexPath);
    Filter filter = null;
    TopDocs topDocs = indexSearcher.search(query, filter, 10000);
    System.out.println("总共有【"+topDocs.totalHits+"】条匹配结果");
       // 3,打印结果
    for(ScoreDoc scoreDoc : topDocs.scoreDocs){
       int docSn = scoreDoc.doc; // 文档内部编号
       Document doc = indexSearcher.doc(docSn); // 根据编号取出相应的文档
       File2DocumentUtils.printDocumentInfo(doc; // 打印出文档信息
    }
}

IndexWriter:操作索引库,增删改
主要方法介绍:

       // 构造方法:如果索引库不存在,会自动创建。如果存在,就使用他
       new IndexWriter(String/Directory indexPath, Analyzer a, MaxFieldLength mfl)
       // 构造方法:第三个参数指定是否创建一个新的索引库。
       // 1,有索引库,create为true:会重新创建。2,没有索引库,create为false,会报错。
       new IndexWriter(String/Directory indexPath, Analyzer a, boolean create, MaxFieldLe
ngth mfl)
       // 添加索引
       addDocument( Document doc )
       // 更新
       updateDocument(Term term, Document doc)
       // 删除
       deleteDocument(Term term)
       // 合并索引库
       addIndexesNoOptimize(Directory[])

今天学了Lucene的入门,明天学习Lucene的高级知识,以及compass框架!
       // 优化索引库
       optimize()
IndexSearcher:操作索引库,查询
       // 构造方法,索引库不存在,就报错
       new IndexSearcher( String indexPath )
       // 搜索
       TopDocs search( Query query, Filter filer, int n )
       // 搜索
       TopDocs search( Query query, Filter filer, int n , Sort sort)
      
Document doc( int docSn )
Documet:Lucene所操作的对象
Field:组成Document的元素,代表一个属性。Store、Index
  new Field( String name, String value, Store store, Index index )

Directory:索引库(目录)
       FSDirectory    :真实的目录
       RAMDirectory:在内存中的一个虚拟的目录
 
QueryParser:把查询字符串变为查询对象的工具。使用子类: MultiFieldQueryParser
      new MultiFieldQueryParser(String[] fields, Analyzer a)
Term:代表某个属性中的一个关键词(目录中出现的条目),是搜索的最小单位
Query :查询对象(封装的过滤条件)。有很多子类,对应各种各样的查询方式。
TopDocs(一套) :代表查询结果
今天知识比较少,可回顾以前的知识,呵呵。。。
posted @ 2010-01-31 23:33 d66380022| 编辑 收藏

徐老师已经把常见的异常在课堂上进行了演示,说实话,这两天都有点郁闷啊,Hibernate咋挺难懂的,老师讲的比较深,一天下来,晚上再看一遍老师的视频,才基本上可以搞清楚课堂上不理解 的知识点。今天讲的双向关联和检索策略。

1.双向关联

1.一对多关联关系

属性方式

2.在昨天的custrom.java中,主要代码:

       private Set<Order> orders = new HashSet<Order>();

      

       public Set<Order> getOrders() {

              return orders;

       }

       public void setOrders(Set<Order> orders) {

              this.orders = orders;

       }

3.Custromer.hbm.xml

<class>中加上:

<set name="orders" lazy="false" inverse="true">

                     <key column="cid" />

                     <one-to-many class="cn.itcast.hibernate.persistence.Order" />

              </set>

 

4.测试: 主要代码:

Customer c = new Customer();

              c.setAge(12);

             

              Order o = new Order();

              o.setOrderNumber("No003");

              o.setPrice(500f);

              //设置关联关系

              o.setCustomer(c);

             

              //s.save(c);

              s.save(o);

 

5.通过Hibernate 查询客户所有订单

 

s.get(Order.class,new Long(1));

debug模式查看所有订单信息

 

注意:双向关联是两端同时进 行

2.操纵持久化对象:

对缓存的理解:首先明白一点:

显式回收:

当没有任何一个对象引用或者指针指向他时,就回收

 

1.当用session 增删改查对象时,用seesion.flush()方法可以实现将数据插入数据库,但不提交事务,。

  之后调用session.clear(),清空本地缓存

 

2.commit()方法默认包含两步操作:先清理缓 存,后提交

 

缓存里放的全是引用

 

s.flush();//清理缓存  以缓存为准,让数据库 和缓存保持同步,让缓存进行一系列增删该查, 改变将进入数据库,但不提交 ,仍然可以回滚等操作

s.refresh();  //刷新缓存  让缓存和数据库保持同步, 以数据库为准,触发一个查询操作,把数据找回来

s.clear();//显式清空    缓存是集合 ,里面放了很多引用,把缓存清掉,为的是释放内存,如果缓存内有指向它的引用,则清掉,但如果缓存外还有其他引用到达他,则不释放内存

 

例如:

Customer c = new Customer(“TOM”,new HashSet());

session.save(c);

Long id = c.getId();

c = null;

Customer c2 = (Customer)session.load(Customer.class,id);

tx.commit();

session.close();

c2.getName(); //这时仍然可以得到name

C2 = null;//之后如果再调用上面的语句,则不能得到name

---------------------------------------------------------------------------------------------

缓存的作用:

1。减少访问数据库的频率。

2。保证缓存中的对象与数据库中的相关记录保持同步。

3。当缓存中的持久化对象之间存在循环关联关系时,Session会保证不出现访问对象图的死循

     还,以及由死循环引起的JVM堆栈溢出异常。

提示:

session加载了customer对象后,会为customer对象的值类型的属性复制一份快照。当清理

缓存时,通过比较对象的当前属性和快照,来判断对象的那些属性发生了变化。

 

3.hibernatejava对象的状态

临时状态(transient):刚刚用new语句创建,没有被持久化,不处于session中。该对象

成为临时对象

持久化状态(persistent):已经被持久化,加入到session的缓存中。该状态的对象为持久

   化对象。

游离状态(detached):已经被持久化,但不处于session中。该状态的对象为游离对象。

注意:sessiondelete方法对于游离对象,该方法从数

      据库中删除记录,对于持久化对象,该方法从数据

      库中删除记录,还要删除缓存中的对象。

   close方法使缓存被清空,缓存中的所有的

      对象都变为游离对象。

游离对象处于内存中

posted @ 2010-01-31 23:32 d66380022| 编辑 收藏
今天讲的是一对一等知识,这两天精力不太好,课堂效率不高,好在下课后还看视频。整理笔记:

一对一:用的较少
 
举例:人员和身份证
设计表
user 存在用户表,photo存在photo表

一对一关联:外键关联
 
另一种方法:主键关联
 
 
注意:constrained = true
多对多:

老师对学生 学生有多个老师
 
只有删除和插入的概念,没有更新的概念

                   
 
 检索方式:
检索方式简介
HQL检索方式
1。7。调用用户自定义的函数
8。嵌入式查询
9。动态绑定参数在查询语句中设定各种查询条件
2。支持投影,仅检索出对象的部分属性
3。支持分页
4。连接查询
5。分组查询
6。内置聚集函数
Query query = session.createQuery(“from Customer as c where c.name=:custoerNa
me and c.age = :customerAge”);
query.setString(“customerName”,”Tom”);
query.setInteger(“customerAge,21);
query.list();

2. QBC检索方式
 
3.多态查询    (查询所有该类以及该类的子类所对应的表,如果查询接口,则查询的是实现的是查询所有实现该接口的类所对应的表

session.createQuery(“from Employee”);
查询出所有的实体
from java.lang.serializable(支持接口)
from java.lang.Object

检索方式简介
对查询结果排序
hql 查询:
session.createQuery(“from Employee c order by c.name”);
qbc查询:
session.createCriteria(Customer.class).addOrder(Order.asc(“id”));

分页查询
hql 查询:
session.createQuery(“from Employee c order by c.name”).setFirstResult(10)
                                   .setMaxResults(10);
qbc查询:
session.createCriteria(Customer.class)
              .addOrder(Order.asc(“name”))
              .setFirstResult(97).setMaxResult(10).list();


检索单个对象
hql 查询:
session.createQuery(“from Employee c order by c.name”)
                     .setMaxResults(1).uniqueResult();
qbc查询:
session.createCriteria(Customer.class)
              .addOrder(Order.asc(“name”))
    .setMaxResult(1).uniqueResult();
 
检索方式简介
对查询结果排序
hql 查询:
session.createQuery(“from Employee c order by c.name”);
qbc查询:
session.createCriteria(Customer.class).addOrder(Order.asc(“id”));

分页查询
hql 查询:
session.createQuery(“from Employee c order by c.name”).setFirstResult(10)
                                   .setMaxResults(10);
qbc查询:
session.createCriteria(Customer.class)
              .addOrder(Order.asc(“name”))
              .setFirstResult(97).setMaxResult(10).list();


检索单个对象
hql 查询:
session.createQuery(“from Employee c order by c.name”)
                     .setMaxResults(1).uniqueResult();
qbc查询:
session.createCriteria(Customer.class)
              .addOrder(Order.asc(“name”))
    .setMaxResult(1).uniqueResult();

绑定参数

hql 查询:
session.createQuery(“from Employee c where c.name =
                              :customerName”);
query.setString(“customer”,”Tom”);

   报表查询
 
小结
比较方面              HQL检索                   QBC检索
可读性           优点:和sql相近,易读         将语句肢解成一组criteria,较差
功能             支持各种查询                  不支持报表查询和子查询。有限的连接查询
查询语句形式     基于字符串形式的sql           更加面向对象
何时被解析       运行时被解析                  编译时被解析,更易排错
可扩展性         不具扩展性                    用户可扩展criteria接口
对动态查询语句的支持 支持动态查询,编程麻烦    适合动态生成查询语句

直接弄个connection ,断点一下,看是否用的c3p0

在学习中一定要不断调试代码!努力消化一天所学!
posted @ 2010-01-31 23:32 d66380022| 编辑 收藏
    AJAX实例

  今天是AJAXweb开 发中的典型应用,也是AJAX的最后一天课,老佟不愧是AJAX的行家,以至于每个班的AJAX都是他带的,老佟讲课风趣极了,课 堂总是不是传来同学们笑声。。。经过三天的js和昨天的AJAX的学习,今天终于可以体现一下无刷新的感觉。

日期验证

1. 日期验证的需求:

    1). birth 输入框中的文字是 "请输入您的生日" , 鼠标获取焦点时, 文本框中的字符变为空格

    2). 当失去焦点时, 若文本框中的字符为空格, 使其值重新设为 "请输入您的生日"

    3). 当失去焦点, 且文本框中的字符不是空格, 且其值发生变化时, 发送 Ajax 请求到服务器端验证输入的日期格式是否合法.

       . 若不合法, 给出 "您输入的日期不合法"

       . 若合法, 给出 "您输入的日期合法"

      

2. Ajax 请求时提示信息  

3.有等待的特效

 

工程整体结构如图:注:使用的是jQuery

 

1.       新建input-date.jsp页面,关键代 码:

2.        

<script type="text/javascript"

src="${pageContext.request.contextPath}/scripts/jquery-1.3.1.js"></script>

<script type="text/javascript">

       $(function(){

              $("#birth").focus(function(){

                     var value = $.trim(this.value);

                     if(value == this.defaultValue){

                            this.value = "";

                     }

              }).blur(function(){

                     var value = $.trim(this.value);

                     if(value == ""){

                            this.value = this.defaultValue;

                     }

              }).change(function(){

                     var value = $.trim(this.value);

                     //再加一个需求:当文本框中的值发生变化, 且其 值不是默认值, 长度在 8 --10 之间, 此时会发送 Ajax 请求

                     if(value != this.defaultValue && value.length >= 8 && value.length <= 10){

                            var url = "${pageContext.request.contextPath }/dateValidateServlet";

                            var args = {time: new Date(), birth: value};

                           

                            $.post(url, args, function(data){

                                   $("#datemsg").html(data);

                            });

                     }else{

                            alert("日期不合法!");

                            this.value = this.defaultValue;

                     }

              });

       });

</script>

</head>

<body>

       <h3>Ajax Validation Example</h3>

       Birth date(yyyy-MM-dd): <input id="birth" type="text" name="birth" value="请输 入您的生日" />

       <br>

       <div id="datemsg"></div>

</body>

2.新建DateValidateServlet,关键代码:

    //1. 获取 birth

              String birth = request.getParameter("birth");

             

              //2. 验证

              Pattern p = Pattern.compile("^((""d{2}(([02468][048])|([13579][26]))[""-""-""s]?((((0?" +

                            "[13578])|(1[02]))[""-""-""s]?((0?[1-9])|([1-2][0-9])|(3[01])))" +

                            "|(((0?[469])|(11))[""-""-""s]?((0?[1-9])|([1-2][0-9])|(30)))|" +

                            "(0?2[""-""-""s]?((0?[1-9])|([1-2][0-9])))))|(""d{2}(([02468][12" +

                            "35679])|([13579][01345789]))[""-""-""s]?((((0?[13578])|(1[02]))" +

                            "[""-""-""s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))" +

                            "[""-""-""s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[""-""-""s]?((0?[" +

                            "1-9])|(1[0-9])|(2[0-8]))))))");

             

              boolean flag = p.matcher(birth).matches();

             

              //3. 根据验证结果返回字符串

              response.setCharacterEncoding("UTF-8");

              PrintWriter out = response.getWriter();

              if(flag){

                     out.println("<font color='green'>日期格式合法</font>");

              }else{

                     out.println("<font color='red'>日期格式不合法</font>");

              }

       }

3.加上特效:

  1.新建文件夹commons,再建ajax.jsp,写代码:

如下

   <script type="text/javascript" src="${pageContext.request.contextPath }/scripts/jquery.blockUI.js"></script>

<script type="text/javascript">

   $().ajaxStart(function(){

          $.blockUI({

            message: $('img#loading'),

            css: {

                top:  ($(window).height() - 150) /2 + 'px',

                left: ($(window).width() - 400) /2 + 'px',

                border: 'none',

                padding: '5px',

                color: '#fff'

            },

              overlayCSS: { backgroundColor: '#fff' }

        });

   }).ajaxStop($.unblockUI);

</script>

<img id="loading" alt=""

   src="${pageContext.request.contextPath }/images/loading.gif" style="display:none" />    

注:代码可参看jquery.blockUI的文档

2.input_date.jsp <head>标签体中加上如下代码:

<%@ include file="/commons/ajax.jsp" %>

3.接着导入jquery.blockUI.js文件

4.最后,便可在tomcat下访问:http://localhost:8080/ajax-1/input-date.jsp ,输入合法日期,结果如图

 

明天是Hibernate的课程。老徐讲的,老徐讲 课之深入已早有所耳闻,且待明天之开始!

posted @ 2010-01-31 23:30 d66380022| 编辑 收藏
                                         AJAX
今天佟刚老师带我们学习了AJAX,AJAX是现在开发的广泛使用的技术,几乎所有的web应用都涉及了该技术,例如,用户名校验,级联下拉列表,下拉树状菜单,在网页无刷新提交等方面有广泛的应用。有前两天的js基础,今天的学习还行 
1.什么是Ajax
Ajax被认为是(Asynchronous JavaScript and XML的缩写)。现在,允许浏览器与服务器通信而无须刷新当前页面的技术都被叫做Ajax.
Ajax这项技术,是Google在Google Labs发布Google Maps和Google Suggest后真正为人所认识。
Ajax应用实例 - Google Suggest

Ajax应用实例 - Google Maps
框架:如果使用一组框架构造了一个网页,可以只更新其中一个框架,而不必惊动整个页面

隐藏的iframe
XMLHttpRequest:该对象是对 JavaScript 的一个扩展,可使网页与服务器进行通信。是创建 Ajax 应用的最佳选择。实际上通常把 Ajax 当成 XMLHttpRequest 对象的代名词
Ajax的工作原理图
Ajax工具包
Ajax并不是一项新技术,它实际上是几种技术,每种技术各尽其职,以一种全新的方式聚合在一起

XMLHttpRequest最早是在IE5中以ActiveX组件的形式实现的。非W3C标准.
  创建XMLHttpRequest对象(由于非标准所以实现方法不统一)
Internet Explorer把XMLHttpRequest实现为一个ActiveX对象
其他浏览器(Firefox、Safari、Opera…)把它实现为一个本地的JavaScript对象。

具体实现流程
:先创建XMLHttpRequest对象
//1. 获取 XMLHttpRequest 对象xhr
//2. 发送 Ajax 请求
//2.1 准备请求: 参数1 -- 请求方式, 参数2 -- 请求路径
xhr.open("GET", url);
//2.2 发送请求, 因为是 GET 请求, 所以不需要发送数据
xhr.send(null);
//3当 XMLHttpRequest 对象的 readyState 属性被服务器改变的时候, 触发 onreadystatechange 事件
//3.1当 XMLHttpRequest 对象的 readyState 属性被服务器改变为 4 的时候表示相应已经完成,
if(xhr.readyState == 4){
//相应完成, 可以获取相应信息: 在 XMLHttpRequest 对象的responseText 属性中包含了相应信息
//可以进一步的控制打印时机: 当相应正确返回时, 即返回的信息码为 200 时
if(xhr.status == 200){
alert(xhr.responseText);
}else{
alert("请求异常...");
}

}

常用状态码及其含义:
• 404 没找到页面(not found)
• 403 禁止访问(forbidden)
• 500 内部服务器出错(internal service error)
• 200 一切正常(ok)
• 304 没有被修改(not modified)
接收相应
responseText
• XMLHttpRequest 的 responseText 属性包含了从服务器发送的数据。它是一个HTML,XML或普通文本,这取决于服务器发送的内容。
• 当 readyState 属性值变成 4 时, responseText 属性才可用,表明 Ajax 请求已经结束。
接收相应
  responseXML
• 如果服务器返回的是 XML, 那么数据将储存在 responseXML 属性中。
• 只用服务器发送了带有正确首部信息的数据时, responseXML 属性才是可用的。 MIME 类型必须为 text/xml

汇总
数据格式提要
  在服务器端 AJAX 是一门与语言无关的技术。在业务逻辑层使用何种服务器端语言都可以。
  从服务器端接收数据的时候,那些数据必须以浏览器能够理解的格式来发送。服务器端的编程语言只能以如下 3 种格式返回数据:
• XML
• JSON
• HTML

对比小结


  若应用程序不需要与其他应用程序共享数据的时候, 使用 HTML 片段来返回数据时最简单的
  如果数据需要重用, JSON 文件是个不错的选择, 其在性能和文件大小方面有优势
  当远程应用程序未知时, XML 文档是首选, 因为 XML 是 web 服务领域的 “世界语”
  jQuery 对 Ajax 操作进行了封装, 在 jQuery 中最底层的方法时 $.ajax(), 第二层是 load(), $.get() 和 $.post(), 第三层是 $.getScript() 和 $.getJSON()
load() 方法

 load() 方法是 jQuery 中最为简单和常用的 Ajax 方法, 能载入远程的 HTML 代码并插入到 DOM 中. 它的结构是: load(url[, data][,callback])。

  明天继续!






posted @ 2010-01-22 00:04 d66380022| 编辑 收藏

  今天AJAX必须用JS,做前端必须用JS,由于课程紧,只安排了一天时间,只讲了Dom

DOM 可在J2SEAPIDocument,便可以查看方法

DOM:节点node)的层次。

  节点分为三种类型:

  节点(node):来源于网络理论,代表网络中的一个连接点。网络是由节点构成的集合

1.节点分为三种类型
  element node    attribute node    text node

2.使用 Aptana 编辑器 :

3.查找节点:

  1)在哪儿写代码:

    不能直接写在<body> 元素的前面 :因为此时 DOM没有被完全解析

    可以把 js 写在 </html> 的后面

    按惯例应该把 js 代码写在 <head>中,<title>节点后,此时需要使用 js 函数window.onload = function(){

              //alert("window.onload...");

              var cityElement = document.getElementById("city");

              alert(cityElement.nodeName);

          };

  2Dom属性:nodeName   nodeType   nodeValue

nodeName:一个字符串,其内容是给定节点的名字。

   var name = node.nodeName;

如果给定节点是一个元素节点或属性节点,nodeName 属性将返回这个元素的名字。

如果给定节点是一个文本节点,nodeName 属性将返回内容为 #text 的字符串。

nodeName 是一个只读属性。

 

nodeType返回一个整数,这个数值代表着给定节点的类型。

nodeType 属性返回的整数值对应着 12 种节点类型:

Node.ELEMENT_NODE (1)      -- 元素节点

Node.ATTRIBUTE_NODE (2)    -- 属性节点

Node.TEXT_NODE (3)         -- 文本节点

nodeType 是个只读属性 

nodeValue返回给定节点的当前值(字符串)

          如果给定节点是一个属性节点,返回值是这个属性的值

          如果给定节点是一个文本节点,返回值是这个文本节点的

   内容。

          如果给定节点是一个元素节点,返回值是 null

          nodeValue 是一个 / 属性,但不能对元素节点的    

   nodeValue 属性设置值,但可以为文本节点的 nodeValue

   属性设置一个值

 

 4. 关于子节点:

       1). 获取方法:

              元素节点的 childNodes 属性可以获取指定元素节点的所有子节点.

       2). 火狐 ie 的实现方式不一样: 火狐包含空格的文本节点    

       3). 提前判断当前节点是否有子节点:

              通过元素节点的 hasChildNodes() 方法. 文本节点和属性节点都没有子节点, 所以他们的 hasChildNodes() 方法总返回 false     

       4). 可以通过元素节点的 firstChild(lastChild) 来获取元素节点的第一个子节点(最后一个子节点)  

可以通过元素节点的 firstChild/lastChild 来获取元素节点的第一个子节点(最后一个节点)            

5. 正则表达式

   用途:

1.        数据有效性验证

2.        查找和替换 

文本格式: /pattern/flags

参数说明:

pattern :一个正则表达式文本

flags : 如果存在,将是以下值:

g global match(全局匹配)

i ignore case(忽略大小写)

gi both global match and ignore case(匹配所有可能的值,也忽略大小写)

 

java中相当重要,可谓必备知识,可惜我这方面没看过,就列

一些常用的正则表达式示例:

 

1、匹配所有的正数:^[0-9]+$

2、匹配所有的小数:^\-?[0-9]*\.?[0-9]*$

3匹配所有的整数:^\-?[0-9]+$

4、提取信息中的中文字符串: [\u4e00-\u9fa5]* ; 

5、提取信息中的邮件地址:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
6
、提取信息中的中国手机号码:(86)*0*13\d{9}
7
、提取信息中的中国固定电话号码:(\(\d{3,4}\)|\d{3,4}-|\s)?\d{8}
8
、提取信息中的中国邮政编码:[1-9]{1}(\d+){5}
9
、提取信息中的中国身份证号码:\d{18}|\d{15}
10
、提取信息中的任何数字:(-?\d*)(\.\d+)?
11
匹配HTML标记的正则表达式:/<(.*)>.*<\/\1>|<(.*) \/>/

 

6. 创建节点:

       1). 创建元素节点: document.createElement

       2). 创建文本节点: document.createTextNode

       3).创建属性节点: 可以直接为其添加属性节点:

              liNode.onclick = function(){

                     alert(this.firstChild.nodeValue);

              };

       4). 插入节点:

              appendChild

              insertBefore

              可以自定义 insertAfter

7. 其它:

       1). 替换节点: replaceChild. **注意: 该方法除了可以替换还可以移动, 一般的, 直接单独使用该方法时并不多.

       2). 删除节点: removeChild

       3). innerHTML属性:   

      

8. 关于 value nodeValue:

       1). value: html 表单元素的某个节点的 value 属性值. <input type="text" value=""> -- value 值可通过 .value 获取; <p value=""></p> 中的 value 属性值无法通过 .value 干获取

       2). nodeValue: 文档(html xml) 中节点的一个属性, 该属性和 nodeType, nodeName 并列. 该属性通常用来获取文本节点的文本值

      

9. 关于 if() 中可以放置的表达式: if 中的表达式为 false, undefined, null, "", 0 时表示不满足条件, 此外都满足条件.     

      

10. 作业: dom-8.html 中的: "为所有的 li 添加 click 事件, 实现 game city 对应位置的 li 子节点的互换"   

 

 

posted @ 2010-01-18 22:20 d66380022| 编辑 收藏

今天内容密度相当大,而且还有点细,知识点比较多。今天是冯老师的最后一天课程,与老冯的将近一个月的接触,老冯讲课有特点:幽默,上课时时不时幽一下,很提神的;声音比较大,以至于老冯有句极像口头禅的“小点声,不然隔壁又找来了”;最重要的是上课的代码每天都有超强的注释,比较有特点的是超强的 readme.txt ,深的同学喜爱;讲课特别敬业,这儿的老师都是特别敬业的。听说老冯呕心沥血,自己做了个项目,年后会公布在网上,到时真的研究研究,相当期待。老师最后给我们了个邮箱,以后有问题,仍然可询问下。

把今天讲的内容总结下,今天讲了昨天留的作业(Struts做的客户信息系统)Struts1.x的验证机制,表单重复提交,同步令牌机制,上传的实现,转换器,国际化内容,由于内容多,只记不会的

1.处理表单重复提交

解决方法:

1. 生成一个唯一的编号,该编号在添加信息的页面存放在隐藏域中

该代码执行后自动添加在customer.jsp页面中添加如下信息 session中保存一份

代码如下:注意:在execute方法中{

//Actionexecute方法开始加上

this.saveToken(request);

//在调用service层增删改查前加从request中获取隐藏域的值

// Stirng gxxxValue=request.getParameter("org.apache.struts.taglib.html.TOKEN");

// 在从session中取出 String keyValue=session.getAttribute("key");

// 如果两个值相等 gxxxValue=keyValue,数据提交

boolean flag=this.isTokenValid(request);

if(flag){

//应该从session中清除session.removeAttribute(key)

this.resetToken(request);

/ /插入数据库的方法以下面一句为例

customerService.saveCustomer(c);

}else{

System.out.println("表单重复提交了");

}

注意:原理:

* request中获取隐藏域的值

Stirng gxxxValue=request.getParameter("org.apache.struts.taglib.html.TOKEN");

* 在从session中取出 String keyValue=session.getAttribute("key");

* 如果两个值相等 gxxxValue=keyValue,数据提交

当数据提交后要从sessioon中删除key sessioon.removeAttribute("key")

2.转换器:

 

当我们在开发时,会遇到数据库中的数据类型和ActionForm中的类型不一致的情况,为减少转换的麻烦,Struts给我们了转换器,她能自动转化很多类型,但遇到如果遇到Date类型就不能转换

 

 

这时要定义转换器

如何定义一个转化器:

1.定义一个类 String2DateConvert implements Converter

重写接口中的方法

2.注册转化器(一定在使用前注册) struts中常用的转换器Struts自己给注册了

实际是把信息放置到一个Map中,原理:

* key是转化数据类型的名称

* 转化器的对象

converters.put(clazz, converter);

converters.put(java.util.Date, new String2Dateconverter());

下面是代码:在Action类中(注意不是在方法体中),加:

static{

/**

* register(new String2DateConvert(), java.util.Date.class);

* 第一个参数是转化器的实例

* 第二个参数要转化的数据类型(本类中用的String-java.util.Date)

*/

ConvertUtils.register(new String2DateConvert(), java.util.Date.class);

}

剩下的就是用Struts自己的,代码:

BeanUtils.copyProperties(与数据库交道的form, 与页面交道的form);

最后

建议:开发中ActionForm中的所有属性定义为String, 不管什么样的数值我都接收,接收到之后在进行检验

3.国际化:

struts中的国际化:

* 定义资源文件

命名规则基名_语言_国家.properties

定义支持中文和英文的资源包

* resource.properties(默认)

* resource_zh_CN.properties

* resource_en_US.properties

把资源包放置到当前web应用的src下,经构建后保存到/WEB-INF/classes目留下

中文要进行编码转化

native2ascii -encoding gb2312源文件目标文件.properites

* struts中如何使用

* struts-config.xml文件中引入 parameter="resource"的值基名

<message-resources parameter="resource"></message-resources>

* jsp页面中如何使用

引入bean标签库

<%@ taglib uri=http://struts.apache.org/tags-bean prefix="bean"%>

<bean:message key="username"/> key 是资源文件中=前面的值

* 如有多个资源文件

* struts-config.xml文件中引入 parameter="resource"的值基名

增加属性key 加以区分

<message-resources

parameter="resource1" key="backup"></message-resources>

*jsp页面中如何使用

<bean:message key="username" bundle="backup"/>

今天就至此了,明天是佟刚老师讲AJAX ,每天都有收获,是我最开心的事情,

好好休息,静待明天的来到!

posted @ 2010-01-17 21:15 d66380022| 编辑 收藏
仅列出标题
共5页: 上一页 1 2 3 4 5 下一页