| « | 三月 2010 | » | ||||
|---|---|---|---|---|---|---|
| 一 | 二 | 三 | 四 | 五 | 六 | 日 |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
| 29 | 30 | 31 | ||||
<script type="text/javascript"
src='<%= renderResponse.encodeURL(renderRequest.getContextPath() + "/dwr/engine.js") %>'>
</script>
<script type="text/javascript"
src='<%= renderResponse.encodeURL(renderRequest.getContextPath() + "/dwr/util.js") %>'>
</script>
<script type="text/javascript"
src='<%= renderResponse.encodeURL(renderRequest.getContextPath() +
"/dwr/interface/RssReader.js") %>'>
</script>
其中的renderRequest和renderResponse是Liferay Portal添加到jsp中的隐含变量,负责对Portlet进行渲染。renderRequest.getContextPath()就是当前jsp的路径,加上js相对于jsp的路径,最后要用renderResponse.encodeURL()方法解码一下才能得到正确的路径。
其他方面,DWR的使用方法就和在一般的jsp中的使用方法一样了。从这里也可以看出,不光是使用DWR,所有对js及其他资源的引用都要用这种方法。
如何实现DWR的多人同时开发
这几天研究了一下DWR,觉的有了这个东东后,Ajax就非常Easy了,可以说是不用学了,我用的是1.1.1的版本,2.0的版本目前还在开发,具体的网址是http://getahead.ltd.uk/dwr/documentation,里面说的很简单,对Web开发比较熟的化,一天就能全学会,不过要做好的话,还是需要在工作中遇到具体的问题再具体解决,再和Spring和Hibernate一结合的化,感觉能大大加快开发进度,现在主要说说如何配置多个dwr.xm,这样的化就可以多个人同时开发,互不影响,这对公司的版本控制还是比较有益处的.
主要是在web.xml中配置
<servlet>
<servlet-name>dwr-user-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>config-user</param-name>
<param-value>WEB-INF/dwr-user.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>dwr-admin-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>config-admin</param-name>
<param-value>WEB-INF/dwr-admin.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dwr-admin-invoker</servlet-name>
<url-pattern>/dwradmin/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>dwr-user-invoker</servlet-name>
<url-pattern>/dwruser/*</url-pattern>
</servlet-mapping>
这样的话在WEB-INF文件夹下就新增两个XML文件,分别为dwr-user.xml,dwr-admin.xml就行了,然后访问:http://localhost:8080/your app/dwruser就能看到它的测试页面了,把它的javascript文件的存放位置拷下来,放到你的JSP或html文件中,就OK了,我觉的这个测试页主要也就是做这个的,它的一些测试方法,我觉的不是很好用.这样就可以同时有多个XML的配置文件,大家同时开发不影响.
最后记住一点,为了搞明白这一点,花了我一下午和晚上的时间,就是在你的web app目录中,不要创建dwruser或dwradmin这样的目录,更不要把Jsp或html放进去,否则的话,不管用绝对还是相对路径都找不到.
1.新建一个webapp,命名为testApp
2.将dwr.jar拷贝到testApp的WEB-INF的lib目录下
3.编译上面的User,UserDAO,DWRUserAccess类,放到classes目录下
4.在web.xml中配置servlet,适配路径到dwr目录下,如下所示
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWR Servlet</display-name>
<description>Direct Web Remoter Servlet</description>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>scriptCompressed</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
以上的配置可以拦截testApp下所有指向dwr的请求,关于这个拦截器,我们会在后面介绍。
5.WEB-INF下新建一个dwr.xml文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd">
<dwr>
<allow>
<create creator="new" javascript="DWRUserAccess">
<param name="class" value="test.DWRUserAccess"/>
</create>
<convert converter="bean" match="test.User"/>
</allow>
</dwr>
这里我们把DWRUserAccess配置到了dwr中,create元素中,creater="new"表示每调用一次DWRUserAccess时,需要new一个这样的类;javascript="DWRUserAccess",表示提供给前台页面调用的javascirpt文件是DWRUserAccess.js。
convert元素用于数据类型转换,即java类和javascript之间相互转换,因为和前台交换的是User对象,因此需要对此使用bean转换,我们将在后面介绍这个类。
DWR嵌入到现有的J2EE(Web)项目的的配置
1、把dwr.jar文件拷贝到项目的lib目录下。
2、修改项目的web.xml文件,在文件中加入以下代码
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
3、在WEB-INF目录中建立dwr.xml文件,例如:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://www.getahead.ltd.uk/dwr/dwr20.dtd">
<dwr>
<init></init>
<allow>
<create creator="new" javascript="dwrbo">
<param name="class" value="com.dwr.DwrBO"/>
</create>
</allow>
</dwr>以上dwr.xml文件内容还是比较好理解。就是发布一个类,一个类发布了,那么就可以通过js 的代码来调用这个类里的方法了。
4、com.dwr.DwrBO类的内容如下:
package com.dwr;
import org.directwebremoting.WebContextFactory;
import uk.ltd.getahead.dwr.ExecutionContext;
public class DwrBO {
public String getInclude()throws Exception{
return WebContextFactory.get().forwardToString("/a.jsp");
}
public String getServerInfo(){
return WebContextFactory.get().getServletContext().getServerInfo()+
"Run on JDK: "+System.getProperty("java.specification.version")+
"Useing DWR :"+ExecutionContext.get().getVersion();
}
public int[] getNumbers(boolean big){
if(big){
System.out.println("big==true");
return new int[]{1000,2000,3000,4000};
}else{
System.out.println("big==false");
return new int[]{1,2,3,4,5,6,7,8,9,10};
}
}
}
这实际上是dwr官方网站上的例子.
5、页面调用代码
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean" %>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles" %>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-template" prefix="template" %>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-nested" prefix="nested" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html:html locale="true">
<head>
<html:base />
<title>测试</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<style type="text/css">
<!--
#Layer1 {
position:absolute;
left:47px;
top:24px;
width:677px;
height:31px;
z-index:1;
}
#context {
position:absolute;
left:45px;
top:100px;
width:679px;
height:100px;
z-index:2;
background-color: #f8f8f8;
clip: rect(10px,auto,auto,auto);
margin-top: 10px;
}
#version {
position: relative;
top: 200px;
width: 200px;
}
#Layer2 {
position:absolute;
left:26px;
top:247px;
width:485px;
height:76px;
z-index:3;
background-color: f2f2f2;
border: 1px solid #f4f4f4;
}
body {
font-size: 12px;
}
-->
</style>
<script type='text/javascript' src='<%=request.getContextPath()%>/dwr/interface/dwrbo.js'></script>
<script type='text/javascript' src='<%=request.getContextPath()%>/dwr/engine.js'></script>
<script type='text/javascript' src='<%=request.getContextPath()%>/dwr/util.js'></script>
<SCRIPT language="javascript">
function loadinfo(data) {
DWRUtil.setValue("context", data);
}
function test(){
dwrbo.getInclude(loadinfo);
}
function loadinfoversion(data){
DWRUtil.setValue("version",data);
}
function showversion(){
dwrbo.getServerInfo(loadinfoversion);
}
function createList(data){
DWRUtil.removeAllOptions("numlist");
DWRUtil.addOptions("numlist",data);
}
function update(){
alert("xxxs");
dwrbo.getNumbers(createList,${"bigselect"}.checked);
}
</SCRIPT>
</head>
<body>
<div id="Layer1">
<input type="submit" name="Submit" value="测试" onClick="test()">
<input type="submit" name="Submit" value="版本信息" onClick="showversion()">
</div>
<div id="context">
</div>
<div id="version">
</div>
<div id="Layer2">
<input type="checkbox" id=bigselect onclick="update()">数字类型<br>
<select id=numlist></select>
</div>
</body>
</html:html>
这只是一个简单的例子,至于具体的技术说明就不说了,因为很简单。把它贴出来当作一个笔记吧,希望能进一步学习DWR
posted on 2006-09-16 16:11 有猫相伴的日子 阅读(238) 评论(3) 编辑 收藏 引用 所属分类: dwr
评论:
# re: DWR2配置及入门例子 2006-10-23 13:19 | 刘文涛[匿名]
按您的教程,没成功,想请问一下 :
<script type='text/javascript' src='<%=request.getContextPath()%>/dwr/interface/dwrbo.js'></script>
<script type='text/javascript' src='<%=request.getContextPath()%>/dwr/engine.js'></script>
<script type='text/javascript' src='<%=request.getContextPath()%>/dwr/util.js'></script>
这些JS 从哪里来啊 ? 回复 更多评论
# re: DWR2配置及入门例子 2006-11-08 08:01 | 有猫相伴的日子
@刘文涛[匿名]
<script type='text/javascript' src='<%=request.getContextPath()%>/dwr/engine.js'></script>
<script type='text/javascript' src='<%=request.getContextPath()%>/dwr/util.js'></script>
这个是DWR自动生成的基础js脚本.
<script type='text/javascript' src='<%=request.getContextPath()%>/dwr/interface/dwrbo.js'></script>
这是跟据我的dwr.xml配置文件生成的,文件的命名与在dwr.xml文件的配置有关 回复 更多评论
工作流要描述步骤(step)、步骤的状态(status)、各个步骤之间的关系以及执行各个步骤的条件和权限,每个步骤中可以含有一个或多个动作(action),动作将会使一个步骤的状态发生改变。
对于一个执行的工作流来讲,步骤的切换是不可避免的。一个工作流在某一时刻会有一个或多个当前步骤,每个当前步骤都有一个状态值,当前步骤的状态值组成了工作流实例的状态值。一旦完成了一个步骤,那么这个步骤将不再是当前步骤(而是切换到一个新的步骤),通常一个新的当前步骤将随之建立起来,以保证工作流继续执行。完成了的步骤的最终状态值是用old-status属性指定的,这个状态值的设定将发生在切换到其他步骤之前。old-status的值可以是任意的,但在一般情况下,我们设置为Finished。
切换本身是一个动作(action)的执行结果。每个步骤可以含有多个动作,究竟要载入哪个动作是由最终用户、外部事件或者triggerd的自动调用决定的。随着动作的完成,一个特定的步骤切换也将发生。动作可以被限制在用户、用户组或当前状态。每一个动作都必须包含一个unconditional result和0个或多个conditional results。
所以,总体来说,一个工作流由多个步骤组成。每个步骤有一个当前状态(例如:Queued, Underway, or Finished),一个步骤包含多个动作。每个步骤含有多个可以执行的动作。每个动作都有执行的条件,也有要执行的函数。动作包含有可以改变状态和当前工作流步骤的results。
(1) Unconditional Result
对于每一个动作来讲,必须存在一个Unconditional Result。一个result是一系列指令,这些指令将告诉OSWorkFlow下一个任务要做什么。这包括使工作流从一个状态切换到另一个状态。
(2) conditional Result
conditional Result是unconditional Result的一个扩展。它需要一个或多个condition子标签。第一个为true的conditional(使用AND或OR类型),会指明发生切换的步骤,这个切换步骤的发生是由于某个用户执行了某个动作的结果导致的。
(3) 三种不同的Results(conditional or unconditional)
--一个新的、单一的步骤和状态的组合。
--一个分裂成两个或多个步骤和状态的组合。
--将这个和其他的切换组合成一个新的单一的步骤和状态的组合。
每种不同的result对应了不同的xml描述,你可以阅读http://www.opensymphony.com/osworkflow/workflow_2_6.dtd,获取更多的信息。
注意:通常,一个split或一个join不会再导致一个split 或 join的发生。
① 单一步骤和状态的结果可以这样描述:
<unconditional-result old-status="Finished" step="2" status="Underway" owner="${someOwner}"/>
如果状态不是Queued的话,那么第三个必要条件就是新步骤的所有者(owner)。除了可以指明下一个状态的信息之外,result也可以指定validators和 post-functions,这将在下面讨论。
② 从一个状态分裂成多个状态可以这样描述:
<unconditional-result split="1"/>
...
<splits>
<split id="1">
<unconditional-result old-status="Finished" step="2"
status="Underway" owner="${someOwner}"/>
<unconditional-result old-status="Finished" step="2"
status="Underway" owner="${someOtherOwner}"/>
</split>
</splits>
③ 将多个状态合并为一个状态可以这样描述:
<!-- for step id 6 ->
<unconditional-result join="1"/>
...
<!- for step id 8 ->
<unconditional-result join="1"/>
...
<joins>
<join id="1">
<conditions type="AND">
<condition type="beanshell">
<arg name="script">
"Finished".equals(jn.getStep(6).getStatus()
&& "Finished".equals(jn.getStep(8).getStatus())
</arg>
</condition>
</conditions>
<unconditional-result old-status="Finished" status="Underway" owner="test" step="2"/>
</join>
</joins>
上面的描述也许有点含糊,但是你最应该关注的是condition标签,它使用一个"jn"的变量,利用这个变量,你可以组成表达式来决定合并动作发生的条件。这个表达式的意思是说:“当id=6和id=8的步骤的状态都变成Finished的状态并且他们要发生的切换都是join="1"时,这个合并动作才发生”。
OSWorkFlow为要定义和执行的外部业务逻辑定义了一个标准的解决方法。这是通过使用"functions"来实现的。OSWorkFlow有两种function,pre和post step functions。
Pre functions是在流程的步骤发生切换之前执行的。一个例子是取得调用者名字的函数,将取得的调用者的名字作为要发生状态切换的result使用。另外一个例子是pre-function用来更新大多数的动作的最近调用者。这两个函数是做为标准的工具函数提供的,在实际的工作流中非常实用。
Post functions与Pre functions有着同样的适用范围,不同点在于Post functions是在状态发生变化之后执行的。一个典型的Post functions的例子是:在某个动作执行完毕后,给某些人发送电子邮件。例如:当一个文档处于'research'步骤,并且执行了'markReadyForReview'动作的时候,要发送邮件给所有的reviewers。
使用Post functions与Pre functions可能有很多原因。一个是如果用户点击完成按钮两次而且发送了两次执行动作的指令,而且这个动作的Pre function会执行很长时间,那么这个长时间执行的函数可能会被执行多次,因为切换动作还没有发生,这时OSWorkflow会认为第二次执行动作是合理的。所以要将这个函数改变成Post function。一般情况下,Pre function应该是简单的、能快速执行的函数。
函数可以定义在两个独立的位置:步骤(step)和动作(action)。
通常情况下,Post functions与Pre functions被定义在action中。在action中定义的Pre-functions是指在该动作发生之前要执行的函数。当工作流发生切换的时候,函数用来做某些事情,不管是发送E_mail也好,还是为以后的使用设置变量。
当Post functions与Pre functions被定义在step中的时候,用途就有点不同了。在step中定义的Pre-functions是指在切换到这个step之前要执行
的函数。注意:这些函数将被应用到这个步骤的所有的切换,即使是由于这个步骤本身发起的切换,例如:在同一个步骤内,由Queued状态转移到Underway状态时,也将调用所有的 Pre functions。与此相同,在step中的Post functions将在流程离开这个步骤之前。
Trigger Functions与其他函数一样,不同点在于他们不是与一个动作相联系的。他们也是通过一个唯一的ID来标识。这些函数通常是运行在系统级用户或非正规用户的环境中。Trigger functions是通过OSWorkflow的API来使用。
validator 是用来校验一个动作的输入的有效性的。如果输入符合条件,那么将执行这个动作。如果输入不符合条件,那么将抛出InvalidInputException异常。
A register 是一个辅助函数,这个函数可以返回一个对象,这个对象可以用在函数中去访问其他的普通对象,特别是出现在workflow中的实体。被注册的对象可以是任何类型,典型的注册对象的例子是:Document, Metadata, Issue, 和Task。
下面是一个registers的例子:
<registers>
<register name="doc" class="com.acme.DocumentRegister"/>
</registers>
...
<results>
<result condition="doc.priority == 1" step="1" status="Underway"
owner="${someManager}"/>
<unconditional-result step="1" status="Queued"/>
</results>
...
Conditions就象validators,registers和functions一样,可以用不同的语言和技术来实现。Conditions可以用AND或OR逻辑运算符来组织。Conditions通常是与conditional results联系的,只有当条件成立,result才会执行。
Conditions与函数很相似,唯一不同的是Conditions返回的是boolean值,而不是void。
在所有的functions、conditions、validators和registers中,可能要提供一系列的参数。这些参数将会被转化为参数Map,这将在后面讨论。同样,在workflow描述符中的status,old-status和owner标签也将被动态的解析成变量。一个变量是这样被识别的:${foo}。当OSWorkflow识别出这种格式的时候,它首先到transientVars中去找关键字为foo的对象,如果没有找到,那么就到propertySet中去找,如果也没找到,那么变量foo将被转换为一个空字串。
One thing of particular importance is that in the case of args, if the variable is the only argument, the argument will not be of type String, but instead whatever the variable type is. However, if the arg is a mix of characters and variables, the entire argument is converted to String no matter what. That means the two arguments below are very different in that foo is a Date object and bar is a String:
<arg name="foo">${someDate}</arg>
<arg name="bar"> ${someDate} </arg> <!-- 注意多余的空格 -->
Permissions can be assigned to users and/or groups based on the state of the workflow instance. These permissions are unrelated to the functionality of the workflow engine, but they are useful to have for applications that implement OSWorkflow. For example, a document management system might have the permission name "file-write-permission" enabled for a particular group only during the "Document Edit" stage of the workflow. That way your application can use the API to determine if files can be modified or not. This is useful as there could be a number of states within the workflow where the "file-write-permission" is applicable, so instead of checking for specific steps or conditions, the check can simply be made for a particular permission.
有的时候,我们需要一些动作可以基于一些条件自动地执行。为了达到这个目的,你可以在action中加入auto="true"属性。流程将考察这个动作的条件和限制,如果条件符合,那么将执行这个动作。 Auto action是由当前的调用者执行的,所以将对该动作的调用者执行权限检查。
建议在你的核心实体中,例如"Document" 或 "Order",在内部创建一个新的属性:workflowId。这样,当新的"Document" 或 "Order"被创建的时候,它能够和一个workflow实例关联起来。那么,你的代码可以通过OSWorkflow API查找到这个workflow实例并且得到这个workflow的信息和动作。
有的时候,为整个workflow实例指定一个状态是很有帮助的,它独立于流程的执行步骤。OSWorkflow提供一些workflow实例中可以包含的"meta-states"。这些"meta-states"可以是CREATED, ACTIVATED, SUSPENDED, KILLED 和 COMPLETED。当一个工作流实例被创建的时候,它将处于CREATED状态。然后,只要一个动作被执行,它就会自动的变成ACTIVATED状态。如果调用者没有明确地改变实例的状态,工作流将一直保持这个状态直到工作流结束。当工作流不可能再执行任何其他的动作的时候,工作流将自动的变成COMPLETED状态。
然而,当工作流处于ACTIVATED状态的时候,调用者可以终止或挂起这个工作流(设置工作流的状态为KILLED 或 SUSPENDED)。一个终止了的工作流将不能再执行任何动作,而且将永远保持着终止状态。一个被挂起了的工作流会被冻结,他也不能执行任何的动作,除非它的状态再变成ACTIVATED。
OSWorkflow部署描述基础
1、基本的格式
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE workflow PUBLIC "-//OpenSymphony Group//DTD OSWorkflow 2.8//EN" "http://www.opensymphony.com/osworkflow/workflow_2_8.dtd">
<workflow>
<initial-actions>
//工作流的开始
</initial-actions>
<steps>
//具体的工作步骤
</steps>
</workflow>
这是一个标准的xml文件,通过定义标准的XML头部,要注意的是OSWorkflow将会通过这些指定的DTD来验证XML内容的合法性。
2、OSWorkflow重要概念是steps (步骤) 和 actions (动作)。
一个步骤是工作流所处的位置,比如一个简单的工作流过程,它可能从一个步骤流转到另外一个步骤(或者有时候还是停留在一样的步骤)。
动作指定了可能发生在步骤内的转变,通常会导致步骤的变更。
简单的说,步骤是“在哪里”,动作是“可以去哪里”。
初始化步骤是一种特殊类型的步骤,它用来启动工作流。在一个工作流程开始前,它是没有状态,不处在任何一个步骤,用户必须采取某些动作才能开始这个流程。这些特殊步骤被定义在 <initial-actions>。
3、工作流状态
Underway - 进行中
Queued - 等候处理中
Finished-完成
4、条件
<action id="1" name="Start First Draft">
<restrict-to>
<conditions>
<condition type="class">
<arg name="class.name">
com.opensymphony.workflow.util.StatusCondition
</arg>
<arg name="status">Queued</arg>
</condition>
</conditions>
</restrict-to>
<results>
<unconditional-result old-status="Finished" status="Underway" step="1"/>
</results>
</action>
上面的条件定义保证了动作1只能在当前状态为“Queued”的时候才能被调用。
4、函数
函数是一个在工作流程中的工作单位,他不会影响到流程本身。函数也可以用来添加变量到当前的环境设置里。变量是一个指定名称的对象,可以用来在工作流中被以后的函数或者脚本使用。
Caller函数会获得当前调用工作流的用户,并把它放入一个名为“caller”的字符型变量中。
<action id="1" name="Start First Draft">
<pre-functions>
<function type="class">
<arg name="class.name">com.opensymphony.workflow.util.Caller</arg>
</function>
</pre-functions>
<results>
<unconditional-result old-status="Finished" status="Underway" step="1" owner="${caller}"/>
</results>
</action>