<html>
<head>
<script type="text/javascript">
var oWD = new ActiveXObject("Word.Application");
var oDC = oWD.Documents.Add("",0,1);
var oRange =oDC.Range(0,1);
function word(id,way){
var sel = document.body.createTextRange();
sel.moveToElementText(id);
sel.select();
sel.execCommand(way);
oRange.Paste();
}
function test(){
var table=document.getElementById('table1');
var table_cells = table.rows[0].cells;
var form_elements = document.getElementById('huahai');
word(div_content,'Copy'); //调用word函数,将div_content范围内容拷贝到word里面。
for(i=0;i<table_cells.length;i++){
oRange =oDC.Range(oRange.End-1,oRange.End); //设定位置依次由上往下、从左往右
var sel = document.body.createTextRange();
sel.moveToElementText(table_cells[i]); //将单元格内容复制到word
sel.select();
sel.execCommand("Copy");
sel.moveEnd('character'); //不加这句导出不了,里面参数为character、不是copy
oRange.Paste();
oRange =oDC.Range(oRange.End-1,oRange.End);
}
oRange =oDC.Range(oRange.End-1,oRange.End); //复制不同的东西,需要写这句继续 写死的这句话就是位置
var img = document.getElementById('img');
word(img,'Copy');//将img范围内容拷贝到word里面。
oRange =oDC.Range(oRange.End-1,oRange.End);
var text_area = document.getElementById('text_area');
word(text_area,'Copy');//将text_area范围内容拷贝到word里面。
oRange =oDC.Range(oRange.End-1,oRange.End);
oWD.Application.Visible = true; //这句意思是所有操作完毕后,在显示出来,如果写在里面,会发现word打开后,什么标签啊、内容啊就跟打字机一样往里面填
}
</script>
</head>
<body>
<form action="" id="huahai" >
<div align="center">
<div align="center" id="div_content">
<h2>
<font color="red">测试导出word</font>
</h2>
<h4>
<font color="red">测试导出word</font>
</h4>
</div>
<table id="table1">
<tr>
<td>姓名</td><td><input type="text" size="5"></td>
<td>年龄</td><td><input type="text" size="5"></td>
</tr>
<table>
<div id="img">
<hr/>
<img src="MM.jpg" height="45%" width="30%">
</br>
</div>
<div id="text_area">
<textarea name="warn_task" wrap="off" cols="80" rows="12">区域内容:</textarea>
</textarea>
<hr />
</div>
<input type="button" onclick="javascript:test();" value="测试">
</div>
</form>
</body>
</html>
"同步模式"就是上一段的模式,后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的;"异步模式"则完全不同, 每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执 行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。
"异步模式"非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。在服务器端,"异步模式"甚至是唯一的模式,因为执行环境是单线程的,如果允许同步执行所有http请求,服务器性能会急剧下降,很快就会失去响应。
本文总结了"异步模式"编程的4种方法,理解它们可以让你写出结构更合理、性能更出色、维护更方便的Javascript程序。
一、回调函数
这是异步编程最基本的方法。
假定有两个函数f1和f2,后者等待前者的执行结果。
如果f1是一个很耗时的任务,可以考虑改写f1,把f2写成f1的回调函数。
function f1(callback){
setTimeout(function () {
// f1的任务代码
callback(); }, 1000);
}
执行代码就变成下面这样:
采用这种方式,我们把同步操作变成了异步操作,f1不会堵塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行。
回调函数的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,程序的流程会很混乱,而且每个任务只能指定一个回调函数。
二、事件监听
另一种思路是采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。
还是以f1和f2为例。首先,为f1绑定一个事件(这里采用的jQuery的写法)。
上面这行代码的意思是,当f1发生done事件,就执行f2。然后,对f1进行改写:
function f1(){
setTimeout(function () {
// f1的任务代码
f1.trigger('done'); }, 1000);
}
f1.trigger('done')表示,执行完成后,立即触发done事件,从而开始执行f2。
这种方法的优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。
三、发布/订阅
上一节的"事件",完全可以理解成"信号"。
我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern),又称"观察者模式"(observer pattern)。
这个模式有多种实现,下面采用的是Ben Alman的Tiny Pub/Sub,这是jQuery的一个插件。
首先,f2向"信号中心"jQuery订阅"done"信号。
jQuery.subscribe("done", f2);
然后,f1进行如下改写:
function f1(){
setTimeout(function () {
// f1的任务代码
jQuery.publish("done"); }, 1000);
}
jQuery.publish("done")的意思是,f1执行完成后,向"信号中心"jQuery发布"done"信号,从而引发f2的执行。
此外,f2完成执行后,也可以取消订阅(unsubscribe)。
jQuery.unsubscribe("done", f2);
这种方法的性质与"事件监听"类似,但是明显优于后者。因为我们可以通过查看"消息中心",了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。
四、Promises对象
Promises对象是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。
简单说,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。比如,f1的回调函数f2,可以写成:
f1要进行如下改写(这里使用的是jQuery的
实现):
function f1(){
var dfd = $.Deferred();
setTimeout(function () {
// f1的任务代码
dfd.resolve();
}, 500);
return dfd.promise;
}
这样写的优点在于,回调函数变成了链式写法,程序的流程可以看得很清楚,而且有一整套的
配套方法,可以实现许多强大的功能。
比如,指定多个回调函数:
再比如,指定发生错误时的回调函数:
而且,它还有一个前面三种方法都没有的好处:如果一个任务已经完成,再添加回调函数,该回调函数会立即执行。所以,你不用担心是否错过了某个事件或信号。这种方法的缺点就是编写和理解,都相对比较难。
第一步,在web.xml中配置DirectJNgine Servlet.我配置的web.xml如下:
在web.xml配置文件中写:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- 以下为DirectJNgine servlet 默认配置-->
<servlet>
<servlet-name>DjnServlet</servlet-name>
<servlet-class>com.softwarementors.extjs.djn.servlet.DirectJNgineServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>providersUrl</param-name>
<param-value>djn/directprovider</param-value>
</init-param>
<!-- DirectJNgine servlet 默认配置-->
<!-- api域:对应下面的各个param-name的前缀,可以设置多个不同的域-->
<init-param>
<param-name>apis</param-name>
<param-value>
mynamespace
</param-value>
</init-param>
<!-- mynamespace对应上面的api域。MyAction对应生成的js相应的文件夹.服务器运行后,将在MyAction/下存放自动生成的3个js文件。这里的名称分别为
MyActionApi.js,MyActionApi-debug.js,MyActionApi-min.js
-->
<init-param>
<param-name>mynamespace.apiFile</param-name>
<param-value>MyAction/MyActionApi.js</param-value>
</init-param>
<!-- mynamespace.对应上面的域."Ext.zhouyang"为命名空间所对应的值。会在页面加载时候用上. -->
<init-param>
<param-name>mynamespace.apiNamespace</param-name>
<param-value>Ext.zhouyang</param-value>
</init-param>
<!-- mynamespace.对应上面的域. 要使用的类的全路径名 -->
<init-param>
<param-name>mynamespace.classes</param-name>
<param-value>
com.softwarementors.extjs.djn.MyAction.MyAction
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DjnServlet</servlet-name>
<url-pattern>/djn/directprovider/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>
index.html
</welcome-file>
</welcome-file-list>
</web-app>
第二步,使你的服务器端方法对JavaScript可见,其实就是说对客户端可见。
以我的demo为例,我想在hello.html中调用服务器端的方法。于是,我在hello.html中添加如下一段话。
<!--以下为DirectJNgine的基础JS文件,放在djn目录下,直接引用就可以。-->
<script type="text/javascript" src="../djn/djn-remote-call-support.js"></script>
<script type="text/javascript" src="../ejn/ejn-assert.js"></script>
<!--以上为DirectJNgine的基础JS文件.-->
<script type="text/javascript" src="MyActionApi.js"></script>
前两个script引用,是用来调用directjngine提供的默认的一些操作函数。只需引用即可,不需要关注太多。
最后一个js,在启动服务器前,你是看不到的。因为它是directjngine项目,根据你的配置自动生成的。至于其中到底是怎样,下面我会详细介绍。
第三步,设计服务器端的方法。如函数名称,是否需要返回值等等。因为在hello.html页面,我将会调用方法。
具体调用代码将在最后的hello.html代码说明部分进行集中说明。
第四步,使用Java语言,编写服务器端的方法。附上代码如下:
- package com.softwarementors.extjs.djn.MyAction;
- import com.softwarementors.extjs.djn.config.annotations.DirectMethod;
- public class MyAction {
- @DirectMethod
- public String doEcho(String parm)
- {
- return "参数是" + parm;
- }
- @DirectMethod
- public String doShow()
- {
- return "i am not easy";
- }
- }
注意:
@DirectMethod这个标签很重要,就是通过这个标签和web.xml的一些配置,才会动态生成第二步中需要引入的js。这种书写方式下, 你在Java代码中书写的方法名称就是你在前台JS调用的方法名称。如果你觉得这样子不安全,或是不专业。那么可以通过定义别名的方法对方法进行访问。书 写形式如下:
@DirectMethod( method="nameyouwant")
这样子定义之后,前台JS调用服务器端方法时,方法的名称就是你红色定义的名称了。
把类编译好后,把class文件放入WEB-INF\classes相应的包目录下。要与web.xml中class文件的包的目录结构相同。
第五步,告诉DirectJNgine 去哪里寻找服务器端的方法。
在web.xml的配置中,有如下代码:
<init-param>
<param-name>mynamespace.classes</param-name>
<param-value>
com.softwarementors.extjs.djn.MyAction.MyAction
</param-value>
</init-param>
在这里需要注意,mynamespace.classes的红色部分,一定要与web.xml上面的apis变量的mynamespace相同。
其次,com.softwarementors.extjs.djn.MyAction.MyAction 为第四步中书写的类的全路径名称,如果有多个类,则用英文逗号分隔。
第六步,为了让Extjs可以调用我们的服务器端方法,我们需要注册一个远程调用提供者即a remoting provider。你需要做的就是在hello.html代码中,加入如下语句,为某一个空间注册一个远程调用提供者:
//此处通过命名空间,添加初始化远程调用API
Ext.zhouyang.REMOTING_API.enableBuffer = 0;
Ext.Direct.addProvider(Ext.zhouyang.REMOTING_API);
注意:上面的Ext.zhouyang为在web.xml变量中mynamespace.apiNamespace已经定义。
第七步,通过JavaScript进行调用服务器端的方法。
MyAction.doShow(function(result, e){
var t = e.getTransaction();
if(e.status){
out.append(
String.format('<p><b>Successful call to {0}.{1} with response:</b><xmp>{2}</xmp></p>',
t.action,
t.method,
Ext.encode(result)));
}else{
out.append(
String.format('<p><b>Call to {0}.{1} failed with message:</b><xmp>{2}</xmp></p>',
t.action,
t.method,
e.message));
}
out.el.scroll('b', 100000, true);
});
//doEcho函数,此函数有参数。
var parm = txtparm.value; //要传入后台的参数
MyAction.doEcho(parm, function(result, e){
var t = e.getTransaction();
if(e.status){
out.append(String.format('<p><b>Successful call to {0}.{1} with response:</b><xmp>{2}</xmp></p>',
t.action, t.method, Ext.encode(result)));
}else{
out.append(String.format('<p><b>Call to {0}.{1} failed with message:</b><xmp>{2}</xmp></p>',
t.action, t.method, e.message));
}
out.el.scroll('b', 100000, true);
});
上面的代码排版有点乱,这里先做些说明,这个demo的下载网址,我最后会附送。可以直接查看代码。
可以看到,对于函数的结构。如果需要传入参数,则把参数写在函数前面。
因为JavaScript调用服务器端方法是异步的,所以,最好的方法就是定义一个回调函数处理数据,而不是让程序终止。
所以,对于上面的两个方法,最后都定义了一个回调函数。这个函数的作用是用来处理服务器端返回的数据。
参数result是服务器端方法返回的数据,e是一个even对象,包括一个事务对象,这个对象包含action和method的名称和其他一些信息。
e.status表示服务器端成功执行了函数。如果返回false,则表示服务器端出现了错误。通过e.message就可以查看出错信息。
其他参数说明:
<init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param>
如果设置为true,在tomcat的log目录下的stdout_2010****.log文件中会输入相关的打印信息。如:
INFO : com.softwarementors.extjs.djn.servlet.DirectJNgineServlet - "Servlet GLOBAL configuration: debug=true, providersUrl=djn/directprovider, minify=true, batchRequestsMultithreadingEnabled=true, batchRequestsMinThreadsPoolSize=16, batchRequestsMaxThreadsPoolSize=80, batchRequestsMaxThreadsPerRequest=8, batchRequestsMaxThreadKeepAliveSeconds=60, gsonBuilderConfiguratorClass=com.softwarementors.extjs.djn.gson.DefaultGsonBuilderConfigurator, dispatcherClass=com.softwarementors.extjs.djn.servlet.ssm.SsmDispatcher, jsonRequestProcessorThreadClass=com.softwarementors.extjs.djn.servlet.ssm.SsmJsonRequestProcessorThread, contextPath=--not specified: calculated via Javascript--, createSourceFiles=true" ()
INFO : com.softwarementors.extjs.djn.servlet.DirectJNgineServlet - "Servlet GLOBAL configuration: registryConfiguratorClass=" ()
INFO : com.softwarementors.extjs.djn.servlet.DirectJNgineServlet - "Servlet APIs configuration: apis=mynamespace" ()
INFO : com.softwarementors.extjs.djn.servlet.DirectJNgineServlet - "Servlet 'mynamespace' Api configuration: apiNamespace=Ext.zhouyang, actionsNamespace=, apiFile=MyAction/MyActionApi.js => Full api file: C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\directdemo\MyAction\MyActionApi.js, classes=com.softwarementors.extjs.djn.MyAction.MyAction" ()
INFO : com.softwarementors.extjs.djn.jscodegen.CodeFileGenerator - "Creating source files for APIs..." ()
如果非调试状态,则可以置为false。
完成上面的步骤后,启动tomcat,发现在\Tomcat 6.0\webapps\directdemo\MyAction 目录下生成了三个文件。
如下:
MyActionApi.js,MyActionApi-debug.js,MyActionApi-min.js。其中的MyActionApi.js就是我们在第二步中引入的JavaScript。
它的作用相当于Server端代码的API一样,因为有它的存在,客户端的网页才知道服务器端都定义了些什么方法。我的demo中,生成的MyActionApi.js的代码如下:
/**********************************************************************
*
* Code generated automatically by DirectJNgine
* Copyright (c) 2009, Pedro Agulló Soliveres
*
* DO NOT MODIFY MANUALLY!!
*
**********************************************************************/
Ext.namespace( 'Ext.zhouyang');
Ext.zhouyang.PROVIDER_BASE_URL=window.location.protocol + '//' + window.location.host + '/' + (window.location.pathname.split('/').length>2 ? window.location.pathname.split('/')[1]+ '/' : '') + 'djn/directprovider';
Ext.zhouyang.POLLING_URLS = {
}
Ext.zhouyang.REMOTING_API = {
url: Ext.zhouyang.PROVIDER_BASE_URL,
type: 'remoting',
actions: {
MyAction: [
{
name: 'doEcho'/*(String) => String */,
len: 1,
formHandler: false
},
{
name: 'doShow'/*() => String */,
len: 0,
formHandler: false
}
]
}
}
可以看到,包括函数名称,参数类型,参数个数等都有定义。
至此,directjngine、Ext Direct调用Java服务器端方法大功告成。
分页查询时加上
itemid = deviceIdCtl.getValue();
rfid1 = rfid.getValue();
if (itemid == undefined || itemid == '')
itemid = "";
if (rfid1 == undefined || rfid1 == '')
rfid1 = "";
typeStore.on("beforeload",function(){ //分页条件不丢失方法
typeStore.baseParams={
'itemid' : itemid,'rfid' : rfid1
}
});
typeStore.load( {
params : {
'itemid' : itemid,
'rfid' : rfid1,
'start' : 0,
'limit' : 20
}
});
JavaScript操作XML是通过XML DOM来完成的 Ie 下面是用ActiveX对象来实现的。
那么什么是XML DOM呢?
XML DOM 是:
- 用于 XML 的标准对象模型
- 用于 XML 的标准编程接口
- 中立于平台和语言
- W3C 的标准
XML DOM 定义了所有XML 元素的对象和属性,以及访问它们的方法(接口)。
也就是说:
XML DOM 是用于查询、添加、修改、删除XML 元素的标准。
ie创建 xml
function xmlcreate() {
var version = [
'MSXML2.DOMDocument6.0',
'MSXML2.DOMDocument3.0',
'MSXML2.DOMDocument'
];
for(var i=0; i<version.length;i++) {
try {
var xml = new ActiveXObject(version[i]);
return xml;
}catch(e) {
}
}
throw new Error('您的系统不支持MSXML库');
}
//载入XML文件,两种方式:1.加载XML字符loadXML();2.加载XML外部文件load()
xml.loadXML('<root>\n<user>Lee</user>\n</root>'); //加载XML字符串
alert(xml.xml);
打印第一个内容 必须用标准DOM
alert(xml.getElementsByTagName('user')[0].firstChild.nodeValue);
加载外部xml
xml.load('a.xml');
动态添加xml
xml.load('a.xml');
var b = xml.createElement('bbb');
var root = xml.documentElement;
root.appendChild(b);
alert(xml.xml);
服务器端 同步/异步
在服务器端 默认用的异步加载 没加载完毕 就打印 肯定出不来
把这个值设为false 就能同步加载了
xml.async = false;
但是如果xml过大 会造成假死状态
不过异步比较好 但是异步又获取不到内容 这该怎么办呢
有个事件
xml.onreadystatechange = function
这个事件可以判断是否加载完成 不过要先载入事件 先把事件加载到内存中 然后再载入xml
事件里面有个属性 xml.readyState 可以判断是否加载完成
这个函数等xml全部加载好 开始处理
xml.onreadystatechange = function() {
if(xml.readyState ==4){ //如果正确就输出
if(xml.parseError == 0) {
alert(xml.xml);
}else { //如果错误 就返回
var a = "错误代码"+xml.parseError.errorCode+'\r\n';
a += "错误行号"+xml.parseError.line+'\r\n';
a += "错误上一行"+xml.parseError.linepos+'\r\n';
a += "错误信息"+xml.parseError.reason+'\r\n';
alert(a);
}
}
}
DOM2操作xml
//create xml 第一个参数 命名空间 第二个 根节点 第三个 文档声明
var xml = document.implementation.createDocument('','root',null); //创建xml
var user = xml.createElement('user');
xml.documentElement.appendChild(user); //插入user
alert(xml.getElementsByTagName('user')[0].tagName); //取得user
dom2也有load方法 默认也是异步的 可以通过设置同步来加载
获取一条信息
var xml = document.implementation.createDocument("",'root',null);
xml.async = false;
xml.load('a.xml');
alert(xml.getElementsByTagName('url')[0].firstChild.nodeValue);
也可以 通过 textContent 不过 ie不支持
alert(xml.getElementsByTagName('url')[0].textContent);
dom如果异步的话 怎么判断是否加载完成呢 可以通过load方法判断 比ie简单了很多
var xml = document.implementation.createDocument("",'root',null);
xml.onload = function(){
alert(xml.getElementsByTagName('url')[0].textContent);
}
xml.load('a.xml');
ps 不过 load 只支持 firefox 和最新版本的opera
但是 w3c提供了2个对象处理xml
var xml = new DOMParser(); //实例化xml对象
var a= "<root><user>gwyy</user></root>";
var xmldom = xml.parseFromString(a,'text/xml'); //通过xml对象创建xml
var seria = new XMLSerializer() //序列号xml
var z = seria.serializeToString(xmldom);
alert(z);
DOM2没有错误对象 出错了 会给你返回一段xml格式的错误信息
//判断错误
var errors = xmldom.getElementsByTagName('parsererror');
if(errors.length > 0) {
throw new Error('错误信息:'+errors[0].textContent);
}
下面是跨浏览器创建xml
//跨浏览器创建
function createxml(xmlstr) {
var xml = null;
if(typeof window.DOMParser != "undefined") {
xml = (new DOMParser).parseFromString(xmlstr,'text/xml');
var errors = xml.getElementsByTagName('parsererror');
if(errors.length > 0){
throw new Error('错误信息:'+errors);
}
} else if(typeof window.ActiveXObject != "undefined") {
var version = [
'MSXML2.DOMDocument6.0',
'MSXML2.DOMDocument3.0',
'MSXML2.DOMDocument'
];
for(var i=0;i<version.length;i++) {
try{
xml = new ActiveXObject(version[i]);
return xml;
}catch(e){
}
}
xml.loadXML(xmlstr);
if(xml.parseError != 0) {
throw new Error('错误信息'+xml.parseError.reason);
}
return xml;
} else {
throw new Error('你的系统或浏览器不支持xml');
}
return xml;
}
//序列化
function serializerXMl(xmlstr) {
var xml = "";
if(typeof window.XMLSerializer != "undefined") {
xml = (new XMLSerializer()).serializeToString(xmlstr);
} else if(typeof xmlstr.xml != "undefined"){
xml = xmlstr.xml;
}
return xml;
}
//实现
var xmlstr = "<root><user>aaaa</user></root>";
var xmldom = createxml(xmlstr);
alert(serializerXMl(xmldom));
为了跨浏览器 xml 只能放弃从外部加载xml
PK 一、常用到的类:
Struts1:
ActionServlet[process()]:当ActionServlet实例接受到HTTP请求之后,在doGet()或doPost()方法都会调用process()方法来处理请求;
RequestProcessor[processPreprocess()]: 当ActionServlet接收到客户请求后,会进行一连串的初始化操作,然后,就会将客户请求转交给合适的处理器进行处理,这个合适的处理器就是 org.apache.struts.action.RequestProcessor,调用processPreprocess()方法该方法不执行任 何操作,直接返回true,子类可以覆盖这个方法,执行客户化的预处理请求操作;
PlugIn:主要用于struts1.x中的过滤器,插件(数据类型转换),国际化等;
Action:ForwardAction、includeAction、DispatchAction、MappingDispatchAction、LookupDispatchAction、SwitchAction的实现接口;
ActionForm:ActionForm用于封装用户的请求参数,而请求参数是通过JSP页面的表单域传递过来的。因此应保证ActionForm的参数,与表单域的名字相同;
ActionForward:ActionForward 是 Struts的核心类之一,其基类仅有4个属性:name / path / redirect / classname。在基于Struts的Web应用程序开发过程中,Action操作完毕后程序会通过Struts的配置文件struts- config.xml链接到指定的ActionForward,传到Struts的核心类ActionServlet,ActionServlet使用 ActionForward提供的路径,将控制传递给下一个步骤。ActionForward控制接下来程序的走向。ActionForward代表一个 应用的URI,它包括路径和参数,例如:path=“/modify.do?method=edit&id=10”;
ActionMapping:将 特定请求映射到特定Action的相关信息存储在ActionMapping中,ActionServelt将ActionMapping传送到 Action类的perform()方法,Action将使用ActionMapping的findForward()方法,此方法返回一个指定名称的 ActionForward,这样Action就完成了本地转发。若没有找到具体的ActionForward,就返回一个null;
struts-config.xml:struts-config.xml是Struts的主要配置文件,在该文件中,可以配置数据源、form-bean、action和plug-in(插件)和资源文件的信息。
-------------------------------------------------------------------------------------------------------------------
Struts2:
FilterDispatcher:org.apache.struts2.dispatcher.FilterDispatcher 是Struts2的主要的Filter,负责四个方面的功能:执行Actions、清除ActionContext、维护静态内容、清除request生 命周期内的XWork的interceptors;
ActionSupport:ActionSupport类是一个工具类,它已经实现了Action接口。除此之外,它还实现了Validateable接口,提供了数据校验功能。通过继承该ActionSupport类,可以简化Struts 2的Action开发。
ServletActionContext[getResponse()]:Struts 2利用ServletActionContext类用来维护Servlet对象,把Servlet对象放到了ServletActionContext 中,例如request、response、application、Session等。ServletActionContext利用 ThreadLocal来维护不同线程的Servlet对象,因此可以使用ServletActionContext类获取到。这种方式也可以叫做非注射 方式(非IoC方式);
ModelDriven[getModel()]:实 现了modelDriven接口可以在action中直接获得例如User对象,它会将ObjectgetModel()取得的User放到 ValueStack中。可以理解为将这个User的属性追加到Action中。它主要是作用是实现类似Struts的FormBean功能;
MethodFilterInterceptor:Struts2提供了一个 MethodFilterInterceptor类对Action中方法过滤的功能,MethodFilterInterceptor是 AbstractInterceptor类的子类,如果要实现拦截器方法过滤功能,则需要继承MethodFilterInterceptor。用户只需 要重写MethodFilterInteceptor中的doInterceptor(ActionInvocation action)即可。其内容实际上与interceptor一样。
struts.xml:struts.xml 为Struts 2的核心配置文件。struts.xml文件主要负责管理应用中的Action映射,以及该Action包含的Result定义等。struts.xml 中主要配置Struts项目的一些全局的属性,用户请求和响应Action之间的对应关系,以及配置Action中可能用到的参数,以及处理结果的返回页 面。还包括各种拦截器的配置等。
======================================================================================================
PK 二、工作流程:
Struts1:
发布Struts Web服务时,根据web.xml初始化ActionServlet,ActionContext等内容.在接到一个HttpRequest请求 后,ActionServlet 根据struts-config.xml中的配置内容,将请求的参数传到对应的Formbean中,并设置session.然后根据请求中的Action 参数,在struts-config.xml中查找指定的Action,并调用此Action来处理请求.根据Action的处理结果,会返回一个forward变量,此时通过mapping.findForward()查找出对应的forward所标示的Action或者JSP页面,将请求转到下一个处理.如果是forward指向JSP页面,则输出到前台.
---------------------------------------------------------------------------------------------------
Struts2:
(1)客户端提交一个HttpServletRequest请求(.action或JSP页面);
(2)请求被提交到一系列Filter过滤器,如ActionCleanUp和FilterDispatcher等;
(3)FilterDispatcher是Struts2控制器的核心,它通常是过滤器链中的最后一个过滤器;
(4)请求发到FilterDispatcher后,FilterDispatcher询问ActionMapper是否需要调用某个Action来处理这个Request(一般根据URL后缀是否为.action来判断);
(5)如果ActionMapper决定需要调用某个Action,FilterDispatcher则把请求交到ActioProxy,由其进行处理;
(6)ActionProxy通过Configuration Manager(它会访问struts.xml)询问框架的配置文件,找到需要调用的Action类;
(7)ActionProxy创建一个ActionInvocation实例,而ActionInvocation通过代理模式调用Action,(在调用之前会根据配置文件加载相关的所有Interceptor拦截器);
(8)Action执行完毕后,返回一个result字符串,此时再按相反的顺序通过Interceptor拦截器;
(9) 最后ActionInvocation负责根据struts.xml中配置的result元素,找到与返回值对应的result,决定进行下一步输出.
PK 三、Struts1和Struts2的区别和对比:
Action 类:
Struts1、要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口。
Struts2、Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个 ActionSupport基类去 实现 常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。
线程模式:
Struts1、 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步 的。
Struts2、Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)。
Servlet 依赖:
Struts1、Action 依赖于Servlet API ,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse被传递给execute方法。
Struts2、Action不依赖于容器,允许Action脱离容器单独被测试。如果需要,Struts2 Action仍然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。
可测性:
Struts1、 测试Struts1 Action的一个主要问题是execute方法暴露了servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测 试)。
Struts2、Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。
捕获输入:
Struts1、 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经 常创建多余的类捕获输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存 在的JavaBean(仍然会导致有冗的 javabean)。
Struts2、 直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过 web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种 ModelDriven 特性简化了taglib对POJO输入对象的引用。
表达式语言:
Struts1、整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。使用标准JSP机制把对象绑定到页面中来访问。
Struts2、Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation Language" (OGNL).绑定值到页面(view)。使用 "ValueStack"技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面(view)。
类型转换:
Struts1、ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的。
Struts2、使用OGNL进行类型转换。提供基本和常用对象的转换器。
校验:
Struts1、支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。 同一个类可以有不同的校验内容,但不能校验子对象。
Struts2、支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性。
Action的执行控制:
Struts1、支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。
Struts2、支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。
xml文件:
Xml代码
<?xml version="1.0" encoding="GB2312"?>
<RESULT>
<VALUE>
<NO>A1234</NO>
<ADDR>河南省郑州市</ADDR>
</VALUE>
<VALUE>
<NO>B1234</NO>
<ADDR>河南省郑州市二七区</ADDR>
</VALUE>
</RESULT>
第一种 DOM 实现方法:
Java代码
import java.io.File; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; public class MyXMLReader2DOM { 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()); System.out.println("运行时间:" + (System.currentTimeMillis() - lasting) + "毫秒"); } } } catch (Exception e) { e.printStackTrace(); } } } |
第二种,DOM4J实现方法:
Java代码
import java.io.*; import java.util.*; import org.dom4j.*; import org.dom4j.io.*; public class MyXMLReader2DOM4J { 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")); } System.out.println("运行时间:" + (System.currentTimeMillis() - lasting) + "毫秒"); } } catch (Exception e) { e.printStackTrace(); } } } |
第三种 JDOM实现方法:
Java代码
import java.io.*; import java.util.*; import org.jdom.*; import org.jdom.input.*; public class MyXMLReader2JDOM { 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()); } System.out.println("运行时间:" + (System.currentTimeMillis() - lasting) + "毫秒"); } } catch (Exception e) { e.printStackTrace(); } } } |
第四种SAX实现方法:
Java代码
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class MyXMLReader2SAX extends DefaultHandler {
java.util.Stack tags = new java.util.Stack();
public MyXMLReader2SAX() {
super();
}
public static void main(String args[]) {
long lasting = System.currentTimeMillis();
try {
SAXParserFactory sf = SAXParserFactory.newInstance();
SAXParser sp = sf.newSAXParser();
MyXMLReader2SAX reader = new MyXMLReader2SAX();
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);
}
}