2008年5月29日
#
删除 ActiveX 控件,请按照相应部分中的步骤操作。
Internet Explorer 3.0、3.01 和 3.02
- 单击“开始”,指向“设置”,单击“控制面板”,双击“添加/删除程序”,然后单击“安装/卸载”选项卡。
- 如果您要删除的 ActiveX 控件出现在安装的程序列表中,请单击该 ActiveX 控件,单击“添加/删除”,然后按照屏幕上的说明操作。如果该 ActiveX 控件没有出现在安装的程序列表中,则继续执行下一步。
- 单击“开始”,单击“运行”,在“打开”框中键入下列行,然后单击“确定”:
regsvr32 drive:\windows\occache\filename.ocx /u
注意:drive 是 Windows 文件夹所在的驱动器号,windows 是安装 Windows 的文件夹名,而 filename.ocx 是您想要删除的 ActiveX 控件。
注意:如果您不知道要删除的 ActiveX 控件 (.ocx) 的文件名,则可以通过查看安装或使用 ActiveX 控件的网页的超文本标记语言 (HTML) 源文件来确定该文件名。要查看一个网页的 HTML 源文件,请右键单击该网页的空白区域,然后单击“查看源文件”。
- 在 Windows 资源管理器或 Windows NT 资源管理器中,单击 Windows\Occache 文件夹中的 .ocx 文件,然后单击“文件”菜单上的“删除”。
Occache 是在 Internet Explorer 3.x 的所有版本中安装有 ActiveX 控件的文件夹的名称。Regsvr32.exe 文件是由 Internet Explorer 安装的,并且可用于注册和删除 ActiveX 控件的注册表项。
Internet Explorer 4.x 或更高版本(所有平台)
Internet Explorer 4.x 或更高版本,包括 Occache.dll 文件,该文件可用于使用“shell 文件夹”枚举、更新和安全地卸载 ActiveX 控件。
- 单击“开始”,指向“设置”,单击“控制面板”,双击“添加/删除程序”,然后单击“安装/卸载”选项卡。
- 如果您要删除的 ActiveX 控件出现在安装的程序列表中,请单击该 ActiveX 控件,单击“添加/删除”,然后按照屏幕上的说明操作。如果该 ActiveX 控件没有出现在安装的程序列表中,则继续执行下一步。
- 在 Windows 资源管理器或 Windows NT 资源管理器中,双击 Windows\Downloaded Program Files 文件夹或 Winnt\Downloaded Program Files 文件夹,右键单击您想要删除的 ActiveX 控件,然后单击“删除”。
- 在系统提示您是否删除该 ActiveX 控件后,单击“是”。
重要说明:如果您运行的是 Internet Explorer 4.0,则不应删除以下 ActiveX 控件:
- DirectAnimation Java Classes
- Internet Explorer Classes for Java
- Microsoft XML Parser for Java
- Win32 Classes
Internet Explorer 5.0 或更高版本不要求 Downloaded Program Files 文件中的这些组件。
删除 ActiveX 控件时出现的错误消息
在您尝试使用 Occache shell 文件夹删除一个 ActiveX 控件时,可能显示以下错误消息之一:
- 共享冲突 这些程序文件当前正由一个或多个程序使用。请关闭一些程序,然后重试。您可能需要重新启动 Windows。
- 组件删除 即将删除 Windows 系统 DLL:(<path\filename>)。是否删除?
共享冲突:
如果您要尝试删除的 ActiveX 控件当前在内存中由 Internet Explorer 或“活动桌面”组件加载,则显示此错误消息。
要解决此错误消息,请按照下列步骤操作:
- 关闭所有打开的 Internet Explorer 窗口。
- 禁用“活动桌面”。为此,请右键单击桌面上的空白区域,指向“活动桌面”,然后单击“查看网页”以清除该复选标记。
- 按照本文中前面部分的“Internet Explorer 4.0 或更高版本”部分中介绍的步骤,删除该 ActiveX 控件。
注意:您最好在删除 ActiveX 控件前重新启动 Windows。
组件删除:
仅当您要删除的 ActiveX 控件向已注册的 Occache 文件夹以外的文件夹(例如,Windows\System 或 Winnt\System32)安装文件时,该消息才出现在 4.01 Service Pack 1 (SP1) 之前的 Internet Explorer 4 版本中。Occache 不是总能确定这些文件是否正由其程序共享。
如果您确定消息中显示的一个或多个文件未由 Windows 或其他程序使用,请单击“是”。否则,单击“否”。
注意:在 Internet Explorer 4.01 SP1 和更高版本中,Occache 不删除(或提示您删除)注册的 Occache 文件夹之外的相关文件。
支持多个 Occache 文件夹
Internet Explorer 4.0 和更高版本支持多个 Occache 文件夹。Occache 文件夹的列表位于以下注册表项中:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ActiveX Cache
默认情况下,Internet Explorer 4.0 和更高版本使用 Windows\Downloaded Program Files 或 Winnt\Downloaded Program Files 文件夹。如果是从 Internet Explorer 3.x 升级的,则 Occache 和 Downloaded Program Files 文件夹可能都存在。在此情况下,所有新的 ActiveX 控件都安装在 Downloaded Program Files 文件夹中,但以前安装的 ActiveX 控件仍在 Occache 文件夹中工作。当您在 Windows 资源管理器、Windows NT 资源管理器或“我的电脑”中打开 Occache 或 Downloaded Program Files 文件夹时,将显示所有 ActiveX 控件,而与该 ActiveX 控件的文件所在的文件夹无关。在此情况下,注册表项中将出现以下字符串值:
"0"="C:\\WINDOWS\\OCCACHE"
"1"="C:\\WINDOWS\\Downloaded Program Files"
有关 ActiveX 控件的其他信息,请参见 Microsoft 知识库中的以下文章:
154544 (http://support.microsoft.com/kb/154544/LN/ ) ActiveX 技术说明
有关 Internet Explorer 在发生冲突(例如,如果文件已存在)时如何下载 ActiveX 控件的信息,请参见 Microsoft 知识库中的以下文章:
196150 (http://support.microsoft.com/kb/196150/LN/ ) INFO:为什么会在代码下载期间创建 CONFLICT 目录
a very cool pdf to word converter:http://www.pdftoword.com
摘要:
<head>
<body>
<table class="dataintable" id='table22'>
<tbody><tr>
&nb...
阅读全文
http://www.ej-technologies.com/products/exe4j/overview.html
window.open(....);
this.focus(); self.opener = this; self.close();
There are two javascript ways to view web site in full screen mode in IE:
1. window.open('http://www.sina.com.cn','','fullscreen')
Note: If view the page remotely, this way will ineffective, and you can use the second one instead.
2. var wsh=new ActiveXObject("wscript.shell");
wsh.run("iexplore -k http://www.google.com");
问题描述:使用ie6导出excel表正常,但是在IE7 下总是报错:“ Automation server can't create
object javascript”。
1. In Internet Explorer > Tools > Internet Options > Security > Custom Level
2. Enabling or prompting "Initializing and Script Activex controls not marked as safe"
3.IE7对环境的设置特别严格,常用到的有两部分,一个是安全里面的“internet”设置,一个是“信任站点”的设置。
1>需要把站点加入信任站点列表;
2>设置“信任站点”项的“自定义级别”,启用“对未标记为可安全执行 ActiveX控件初始化并执行脚本”即可。
|
#2
|
|
The children of a TabNavigator aren't
created until they're needed. In your case, only the contents of the
first tab are actually created, because they're part of what's needed
when the TabNavigator is first displayed. The contents of the second tab
won't be instantiated until they need to be displayed, which is when
the second tab is clicked on. That's why that error is being thrown
until you click on the second tab. This process of only instantiating
components as they are needed is called deferred instantiation.
To force the contents of the other tabs to be instantiated, try changing
the creationPolicy property of the TabNavigator to be "all". This will
cause all of the different tabs to be instantiated, regardless of having
been clicked on.
In the Flex docs, check out Container.creationPolicy for more details.
ActionScript Code:
<mx:TabNavigator creationPolicy="all">
|
W3C DOM Compatibility - CSS
From: http://www.quirksmode.org/dom/w3c_css.html#access
From:http://martybugs.net/articles/print.cgi
Web Page Printability With CSS
author: Martin
"mpot" Pot
date: 7 January 2005
Introduction
This article describes how to use CSS media types to make your website
much more
printer-friendly.
An overview of CSS media types is given, and sample HTML and CSS code is
provided,
detailing how to implement CSS media types for improving printability.
Why?
Most webpages do not print very well, with large amounts of the printed
page being wasted with
banners, navigation menus, advertising, and other unnecessary content.
When attempting to print out the main text of a webpage, you often have
to resort to
copying the text into Word or another editor, and then printing it.
Some websites make use of a link at the bottom of the page, linking to a
"printable version"
of the same page. However, this requires additional effort on the part
of the web developer.
There is a much easier way to make your pages print better, and that's
via the use of
CSS media types.
For example, all content on
MartyBugs.Net
has been designed to be
printer-friendly.
When printing pages from this site
using a modern browser, elements such as the left menu column and the
right column (where used)
will be hidden, thus ensuring there's more room on the printed page for
the main content.
|
page as displayed on a 1024x768 screen
|
The image above shows how one of the pages on this website would be
displayed on a
computer screen, at a resolution of 1024x768.
|
|
|
printed page,
no print optimisation
|
|
printed page,
optimised for printing
|
The left image above shows how the same page will look when printed, if
all the page content is printed.
Notice how little room there is in the centre of the page for the main
content.
The right image above shows the same page, but the navigation and other
content on the left and right
hand sides of the page is not printed. CSS media types have been used
to hide this content when
the page is printed.
CSS Media Types
The primary aim of the CSS media types is to allow the web-page author
to define different styles for
a page, depending on the media being used to display the page.
CSS 2.1 supports numerous media types, including
all (suitable for all devices),
screen (computer screens),
print (pages viewed on-screen in print-preview mode and printed
pages).
Other less-common media types are also supported, such as braille,
embossed, handheld, projection,
speech, etc, but we won't be discussing any of these.
CSS media types are defined using the rule in
your CSS style-sheet,
or in your in-line CSS style definitions.
For example, to define different font sizes for the
print
and
screen media types, as well as a common
line-height to be used for both,
the CSS definition is as follows:
@media print {
body { font-size: 10pt }
}
@media screen {
body { font-size: 13px }
}
@media screen, print {
body { line-height: 1.2 }
}
The CSS media types allow you to specify different CSS properties for
any element, so it will be
displayed differently on the screen than when printed.
For the purposes of this article, the only thing we're interested in is
to hide some page elements
when the page is printed.
Refer to the
W3C CSS
2.1 Media Definitions
for more details on CSS media types.
Using CSS Media Types
The web pages on this website are all generated on-the-fly, using
server-side Perl templates.
All pages have a number of common elements, namely:
- a banner across the top
- navigation menu on the left side
- main content in the centre
- advertising and other content on the right side
- footer across the bottom
When someone prints out a page from this website, CSS media types are
used to hide a number
of elements on the page, including the navigation menu, advertising, and
the navigation content
in the footer.
To provide a working demonstration of how CSS media types can be used in
this way, a demonstration
web page was coded, using tables to define the banner area across the
top of the page, with
a column down the left-hand side for the navigation menu, a column down
the right-hand side
for other content, and a footer across the bottom of the page.
This layout is one of the most commonly used page layouts on the
internet at the present - hence
my choice to use it as an example.
the example page
Firstly, we define the CSS styles for the page:
<style type="text/css">
@media print {
.noprint { display: none; }
}
</style>
Note that the CSS styles can also be defined using a separate CSS file,
but example page has the CSS
defined in-line for simplicity (and to keep the example to a single
file).
The above CSS definition is defining a style called
noprint,
and will only
be applied to printed content. Setting the
display
property to
none means any content using this CSS style
will not be displayed
when printed, but will be displayed for all other media types.
There are a number of components on this page that we don't want
printed, namely the columns on the
left-hand side and on the right-hand side.
The
noprint style is applied to the table
cells holding this content,
thus ensuring they won't be visible when the page is printed.
<table border='1' cellpadding='4' cellspacing='0' width='100%' >
<tr height='60'><td colspan='3'>
banner place-holder
</td></tr>
<tr><td width='150' valign='top' class='noprint'>
left-side content place-holder
</td><td>
<b>main content</b>
[snip!]
</td><td width='150' valign='top' class='noprint'>
right-side content place-holder
</td></tr><tr><td colspan='3'>
footer content place-holder
</td></tr>
</table>
This will result in the columns on the left and right-hand sides being
hidden when the page
is printed, thus providing more space on the printed page for the
content itself.
Note that this style needs to be applied to the table cells themselves,
and not just to the content
in these table cells, else the (empty) cells will still show up on the
printed copy.
Testing Your CSS
The easiest way to test CSS styles for print media is to use a web
browser which has print preview
capabilities.
The print preview will give you a fairly accurate representation of how
the page will look
when it is printed, and is a much more efficient way to test your media
styles, rather than
actually printing out pages on a printer.
Most popular web browsers should support print preview functionality.
The
FireFox
browser has print preview functionality, although it lacks any
zoom/unzoom capabilities.
As an alternative to using print preview, you can print the web page to a
PDF file.
There are numerous (costly, freeware, and anywhere in between) software
packages for
doing this.
I recommend using the freeware and open-source
PDFCreator,
which is
a Windows printer driver which allows you to create PDFs from any
Windows application, just by
selecting the PDFCreator driver as the virtual printer from that
application.
Also be sure to use the
W3C's
free
CSS
Validation Service to
check your CSS definitions.
References
http://support.microsoft.com/kb/973904
Let me fix it myself
To unregister the mswrd632 converter yourself, edit the registry as follows:
- Click Start, click Run, type regedit, and then click OK.
- Locate and then click the following registry subkey:
- For 32-bit versions of Windows:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Text Converters\Import\MSWord6.wpc
- For 64-bit versions of Windows:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Shared Tools\Text Converters\Import\MSWord6.wpc
- On the Edit menu, click Delete.
- Click Yes.
- Exit Registry Editor.
This change will effectively unregister the converter and disable it for third-party applications and for Microsoft Office. Microsoft Office will use its own text converters to open these kinds of files.
The user was running Office 2007 and getting this error. After doing some research, we came across a few possible solutions. In this post, I’ll list them out here.
Method 1 – Unregister Text Converter
Basically, in Windows XP SP2 and above and Windows Server 2003 SP1 and above, if you have a plain text file or another kind of file that is not a Microsoft Word file, but has a .doc extension, you will get this error.
This can also happen if you are opening a really old document created by Word for Windows 6.0 or Word 97 documents. In this case, you can disable the mswrd632 converter so you don’t get this error. The files will then be opened by the Microsoft Office text converters.
You can unregister this converter by going to Start, then run and typing regedit. Then navigate to the following key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Text Converters\Import\MSWord6.wpc
Right-click on the MSWord6.wpc key in the left hand pane and choose Delete. If you have a Word 97 document, you should still be able to open it in Word 2003 or 2007. However, you will not be able to open these files in WordPad anymore. You’ll get an error like:
Cannot load Word for Windows 6.0 files
If you really have to use WordPad to open Word 6.0/95 files, you can re-enable the Word 6.0/95 for Windows and Macintosh to RFT converter. Open the registry and go to the following keys:
For 32-bit versions of Windows
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\ Applets\Wordpad
For Microsoft Windows on Windows 64 (WOW) mode
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\ CurrentVersion\Applets\Wordpad
If the Wordpad key is not there in the left-hand pane, create it. After that, create a new DWORD value in the right-pane called AllowConversion and give it a value of 1.
Method 2 – Copy the MSWrd632.wpc File
The other way to solve this issue is to copy the MSWrd632.wpc file from another computer to the computer having problems.
The only issue with this is that it is less secure and makes your computer vulnerable to a possible security hack, so don’t do this unless you really have to or that computer is not connected to the Internet.
You can usually find this file in the following path:
C:\Program Files\Common Files\Microsoft Shared\TextConv\
That’s about it! If you are still having this problem, post a comment here and I’ll try to help! Enjoy!
详解COM Add In的LoadBehavior及其妙用
http://blog.csdn.net/v_jzho/archive/2007/10/06/1813080.aspx
基于Visual Studio 2003/2005的Office插件开发FAQ
http://blog.csdn.net/tonyqus/archive/2007/02/24/1513256.aspx
There are several ways to deploy an assembly into the global assembly
cache:
1) Use an installer designed to work with the global assembly cache. This
is the preferred option for installing assemblies into the global assembly
cache
2) Use a developer tool called the Global Assembly Cache tool (Gacutil.exe)
provided by the .NET Framework SDK.
3) Use Windows Explorer to drag and drop assemblies into the cache.
4) use install shield. (注意:installshield里只有msi等几个类型的项目支持这个)
From:http://bytes.com/topic/net/answers/109942-deploy-assembly-gac
http://www.microsoft.com/downloads/details.aspx?familyid=59DAEBAA-BED4-4282-A28C-B864D8BFA513&displaylang=en
http://msdn.microsoft.com/en-us/library/15s06t57(VS.80).aspx
The 'AllOtherFiles' is an entry automatically created when you check the GlobalAssemblyCache predefined folder. After you add in your file(s), perform the following steps:
1. Right-click "Destination Computer"
2. Check "Show Components"
3. Expand the [GlobalAssemblyCache] tree.
4. Delete the "AllOtherFiles" entry.
正则表达式(regular expression)
关键字:
正则表达式,Regular Expression
作者:笑容
发表于:2004年05月03日
最后更新:2005年01月17日
19:54
版权声明:使用创作公用版权协议
引用地址:<a
href="http://oo8h.51.net/docs/regular_expression.htm">正则表达式(regular
expression)</a>
NAV: 笑容的八小时外 / 笑容的八小时外资料索引
如何创建一个网站 (HOW TO:
Initiate a website) Red Hat Enterprise
Linux 介绍
前言
正则表达式是烦琐的,但是强大的,学会之后的应用会让你除了提高效率外,会给你带来绝对的成就感。只要认真去阅读这些资料,加上应用的时候进行一定的参考,掌握正则表达式不是问题。
索引
1._引子
2._正则表达式的历史
3._正则表达式定义
3.1_普通字符
3.2_非打印字符
3.3_特殊字符
3.4_限定符
3.5_定位符
3.6_选择
3.7_后向引用
4._各种操作符的运算优先级
5._全部符号解释
6._部分例子
7._正则表达式匹配规则
7.1_基本模式匹配
7.2_字符簇
7.3_确定重复出现
目前,正则表达式已经在很多软件中得到广泛的应用,包括*nix(Linux,
Unix等),HP等操作系统,PHP,C#,Java等开发环境,以及很多的应用软件中,都可以看到正则表达式的影子。
正则表达式的使用,可以通过简单的办法来实现强大的功能。为了简单有效而又不失强大,造成了正则表达式代码的难度较大,学习起来也不是很容易,所以需要付出一些努力才行,入门之后参照一定的参考,使用起来还是比较简单有效的。
例子: ^.+@.+""..+$
这样的代码曾经多次把我自己给吓退过。可能很多人也是被这样的代码给吓跑的吧。继续阅读本文将让你也可以自由应用这样的代码。
注意:这里的第7部分跟前面的内容看起来似乎有些重复,目的是把前面表格里的部分重新描述了一次,目的是让这些内容更容易理解。
正则表达式的“祖先”可以一直上溯至对人类神经系统如何工作的早期研究。Warren
McCulloch 和 Walter Pitts 这两位神经生理学家研究出一种数学方式来描述这些神经网络。
1956 年, 一位叫 Stephen Kleene 的数学家在 McCulloch 和 Pitts
早期工作的基础上,发表了一篇标题为“神经网事件的表示法”的论文,引入了正则表达式的概念。正则表达式就是用来描述他称为“正则集的代数”的表达式,因此采用“正则表达式”这个术语。
随后,发现可以将这一工作应用于使用 Ken Thompson 的计算搜索算法的一些早期研究,Ken Thompson 是 Unix
的主要发明人。正则表达式的第一个实用应用程序就是 Unix 中的 qed 编辑器。
如他们所说,剩下的就是众所周知的历史了。从那时起直至现在正则表达式都是基于文本的编辑器和搜索工具中的一个重要部分。
正则表达式(regular
expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。
- 列目录时, dir *.txt或ls
*.txt中的*.txt就不是一个正则表达式,因为这里*与正则式的*的含义是不同的。
正则表达式是由普通字符(例如字符 a 到
z)以及特殊字符(称为元字符)组成的文字模式。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
由所有那些未显式指定为元字符的打印和非打印字符组成。这包括所有的大写和小写字母字符,所有数字,所有标点符号以及一些符号。
字符 |
含义 |
"cx |
匹配由x指明的控制字符。例如, "cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z
或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。 |
"f |
匹配一个换页符。等价于 "x0c 和 "cL。 |
"n |
匹配一个换行符。等价于 "x0a 和 "cJ。 |
"r |
匹配一个回车符。等价于 "x0d 和 "cM。 |
"s |
匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ "f"n"r"t"v]。 |
"S |
匹配任何非空白字符。等价于 [^ "f"n"r"t"v]。 |
"t |
匹配一个制表符。等价于 "x09 和 "cI。 |
"v |
匹配一个垂直制表符。等价于 "x0b 和
"cK。 |
所谓特殊字符,就是一些有特殊含义的字符,如上面说的"*.txt"中的*,简单的说就是表示任何字符串的意思。如果要查找文件名中有*的文件,则需要对*进行转义,即在其前加一个"。ls
"*.txt。正则表达式有以下特殊字符。
特别字符 |
说明 |
$ |
匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配
'"n' 或 '"r'。要匹配 $ 字符本身,请使用 "$。 |
( ) |
标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 "( 和
")。 |
* |
匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 "*。 |
+ |
匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 "+。 |
. |
匹配除换行符 "n之外的任何单字符。要匹配 .,请使用 "。 |
[ |
标记一个中括号表达式的开始。要匹配 [,请使用 "[。 |
? |
匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用
"?。 |
" |
将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, 'n' 匹配字符
'n'。'"n' 匹配换行符。序列 '""' 匹配 """,而 '"(' 则匹配 "("。 |
^ |
匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^
字符本身,请使用 "^。 |
{ |
标记限定符表达式的开始。要匹配 {,请使用 "{。 |
| |
指明两项之间的一个选择。要匹配 |,请使用 "|。 |
- 构造正则表达式的方法和创建数学表达式的方法一样。也就是用多种元字符与操作符将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。
限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有*或+或?或{n}或{n,}或{n,m}共6种。
*、+和?限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个?就可以实现非贪婪或最小匹配。
正则表达式的限定符有:
字符 |
描述 |
* |
匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。*
等价于{0,}。 |
+ |
匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配
"z"。+ 等价于 {1,}。 |
? |
匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does"
中的"do" 。? 等价于 {0,1}。 |
{n} |
n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的
'o',但是能匹配 "food" 中的两个 o。 |
{n,} |
n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配
"foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。 |
{n,m} |
m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m
次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于
'o?'。请注意在逗号和两个数之间不能有空格。 |
用来描述字符串或单词的边界,^和$分别指字符串的开始与结束,"b描述单词的前或后边界,"B表示非单词边界。
不能对定位符使用限定符。
用圆括号将所有选择项括起来,相邻的选择项之间用|分隔。但用圆括号会有一个副作用,是相关的匹配会被缓存,此时可用?:放在第一个选项前来消除这种副作用。
其中?:是非捕获元之一,还有两个非捕获元是?=和?!,这两个还有更多的含义,前者为正向预查,在任何开始匹配圆括号内的正则表达式模式的位置来匹配搜索字符串,后者为负向预查,在任何开始不匹配该正则表达式模式的位置来匹配搜索字符串。
对一个正则表达式模式或部分模式两边添加圆括号将导致相关匹配存储到一个临时缓冲区中,所捕获的每个子匹配都按照在正则表达式模式中从左至右所遇到的内容存储。存储子匹配的缓冲区编号从
1 开始,连续编号直至最大 99 个子表达式。每个缓冲区都可以使用 '"n' 访问,其中 n
为一个标识特定缓冲区的一位或两位十进制数。
可以使用非捕获元字符 '?:', '?=', or '?!' 来忽略对相关匹配的保存。
相同优先级的从左到右进行运算,不同优先级的运算先高后低。各种操作符的优先级从高到低如下:
操作符 |
描述 |
" |
转义符 |
(), (?:), (?=), [] |
圆括号和方括号 |
*, +, ?, {n}, {n,}, {n,m} |
限定符 |
^, $, "anymetacharacter |
位置和顺序 |
| |
“或”操作 |
字符 |
描述 |
" |
将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,'n'
匹配字符 "n"。'"n' 匹配一个换行符。序列 '""' 匹配 """ 而 ""(" 则匹配 "("。 |
^ |
匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配
'"n' 或 '"r' 之后的位置。 |
$ |
匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '"n'
或 '"r' 之前的位置。 |
* |
匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。*
等价于{0,}。 |
+ |
匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配
"z"。+ 等价于 {1,}。 |
? |
匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does"
中的"do" 。? 等价于 {0,1}。 |
{n} |
n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的
'o',但是能匹配 "food" 中的两个 o。 |
{n,} |
n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配
"foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。 |
{n,m} |
m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m
次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于
'o?'。请注意在逗号和两个数之间不能有空格。 |
? |
当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m})
后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?'
将匹配单个 "o",而 'o+' 将匹配所有 'o'。 |
. |
匹配除 ""n" 之外的任何单个字符。要匹配包括 '"n' 在内的任何字符,请使用象 '[."n]'
的模式。 |
(pattern) |
匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches
集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 '"(' 或
'")'。 |
(?:pattern) |
匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用
"或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries'
更简略的表达式。 |
(?=pattern) |
正向预查,在任何匹配 pattern
的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,'Windows (?=95|98|NT|2000)' 能匹配
"Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的
"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?!pattern) |
负向预查,在任何不匹配 pattern
的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配
"Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的
"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始 |
x|y |
匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配
"zood" 或 "food"。 |
[xyz] |
字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的
'a'。 |
[^xyz] |
负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain"
中的'p'。 |
[a-z] |
字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z'
范围内的任意小写字母字符。 |
[^a-z] |
负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到
'z' 范围内的任意字符。 |
"b |
匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er"b' 可以匹配"never" 中的
'er',但不能匹配 "verb" 中的 'er'。 |
"B |
匹配非单词边界。'er"B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的
'er'。 |
"cx |
匹配由 x 指明的控制字符。例如, "cM 匹配一个 Control-M 或回车符。x 的值必须为
A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。 |
"d |
匹配一个数字字符。等价于 [0-9]。 |
"D |
匹配一个非数字字符。等价于 [^0-9]。 |
"f |
匹配一个换页符。等价于 "x0c 和 "cL。 |
"n |
匹配一个换行符。等价于 "x0a 和 "cJ。 |
"r |
匹配一个回车符。等价于 "x0d 和 "cM。 |
"s |
匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ "f"n"r"t"v]。 |
"S |
匹配任何非空白字符。等价于 [^ "f"n"r"t"v]。 |
"t |
匹配一个制表符。等价于 "x09 和 "cI。 |
"v |
匹配一个垂直制表符。等价于 "x0b 和 "cK。 |
"w |
匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 |
"W |
匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。 |
"xn |
匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,'"x41' 匹配
"A"。'"x041' 则等价于 '"x04' & "1"。正则表达式中可以使用 ASCII 编码。. |
"num |
匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)"1'
匹配两个连续的相同字符。 |
"n |
标识一个八进制转义值或一个向后引用。如果 "n 之前至少 n 个获取的子表达式,则 n
为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。 |
"nm |
标识一个八进制转义值或一个向后引用。如果 "nm 之前至少有 nm 个获得子表达式,则 nm
为向后引用。如果 "nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则
"nm 将匹配八进制转义值 nm。 |
"nml |
如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值
nml。 |
"un |
匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, "u00A9
匹配版权符号 (?)。 |
正则表达式 |
说明 |
/"b([a-z]+) "1"b/gi |
一个单词连续出现的位置 |
/("w+):"/"/([^/:]+)(:"d*)?([^# ]*)/ |
将一个URL解析为协议、域、端口及相对路径 |
/^(?:Chapter|Section) [1-9][0-9]{0,1}$/ |
定位章节的位置 |
/[-a-z]/ |
A至z共26个字母再加一个-号。 |
/ter"b/ |
可匹配chapter,而不能terminal |
/"Bapt/ |
可匹配chapter,而不能aptitude |
/Windows(?=95 |98 |NT )/ |
可匹配Windows95或Windows98或WindowsNT,当找到一个匹配后,从Windows后面开始进行下一次的检索匹配。 |
7.1
基本模式匹配
一切从最基本的开始。模式,是正规表达式最基本的元素,它们是一组描述字符串特征的字符。模式可以很简单,由普通的字符串组成,也可以非常复杂,往往用特殊的字符表示一个范围内的字符、重复出现,或表示上下文。例如:
^once
这个模式包含一个特殊的字符^,表示该模式只匹配那些以once开头的字符串。例如该模式与字符串"once upon a time"匹配,与"There
once was a man from NewYork"不匹配。正如如^符号表示开头一样,$符号用来匹配那些以给定模式结尾的字符串。
bucket$
这个模式与"Who kept all of this cash in a
bucket"匹配,与"buckets"不匹配。字符^和$同时使用时,表示精确匹配(字符串与模式一样)。例如:
^bucket$
只匹配字符串"bucket"。如果一个模式不包括^和$,那么它与任何包含该模式的字符串匹配。例如:模式
once
与字符串
There once was a man from NewYork
Who kept all of his cash in a
bucket.
是匹配的。
在该模式中的字母(o-n-c-e)是字面的字符,也就是说,他们表示该字母本身,数字也是一样的。其他一些稍微复杂的字符,如标点符号和白字符(空格、制表符等),要用到转义序列。所有的转义序列都用反斜杠(")打头。制表符的转义序列是:"t。所以如果我们要检测一个字符串是否以制表符开头,可以用这个模式:
^"t
类似的,用"n表示“新行”,"r表示回车。其他的特殊符号,可以用在前面加上反斜杠,如反斜杠本身用""表示,句号.用".表示,以此类推。
7.2
字符簇
在INTERNET的程序中,正规表达式通常用来验证用户的输入。当用户提交一个FORM以后,要判断输入的电话号码、地址、EMAIL地址、信用卡号码等是否有效,用普通的基于字面的字符是不够的。
所以要用一种更自由的描述我们要的模式的办法,它就是字符簇。要建立一个表示所有元音字符的字符簇,就把所有的元音字符放在一个方括号里:
[AaEeIiOoUu]
这个模式与任何元音字符匹配,但只能表示一个字符。用连字号可以表示一个字符的范围,如:
[a-z] //匹配所有的小写字母
[A-Z] //匹配所有的大写字母
[a-zA-Z] //匹配所有的字母
[0-9]
//匹配所有的数字
[0-9"."-] //匹配所有的数字,句号和减号
[ "f"r"t"n] //匹配所有的白字符
同样的,这些也只表示一个字符,这是一个非常重要的。如果要匹配一个由一个小写字母和一位数字组成的字符串,比如"z2"、"t6"或"g7",但不是"ab2"、"r2d3"
或"b52"的话,用这个模式:
^[a-z][0-9]$
尽管[a-z]代表26个字母的范围,但在这里它只能与第一个字符是小写字母的字符串匹配。
前面曾经提到^表示字符串的开头,但它还有另外一个含义。当在一组方括号里使用^是,它表示“非”或“排除”的意思,常常用来剔除某个字符。还用前面的例子,我们要求第一个字符不能是数字:
^[^0-9][0-9]$
这个模式与"&5"、"g7"及"-2"是匹配的,但与"12"、"66"是不匹配的。下面是几个排除特定字符的例子:
[^a-z] //除了小写字母以外的所有字符
[^"""/"^] //除了(")(/)(^)之外的所有字符
[^"""']
//除了双引号(")和单引号(')之外的所有字符
特殊字符"."
(点,句号)在正规表达式中用来表示除了“新行”之外的所有字符。所以模式"^.5$"与任何两个字符的、以数字5结尾和以其他非“新行”字符开头的字符串匹配。模式"."可以匹配任何字符串,除了空串和只包括一个“新行”的字符串。
PHP的正规表达式有一些内置的通用字符簇,列表如下:
字符簇 含义
[[:alpha:]] 任何字母
[[:digit:]] 任何数字
[[:alnum:]] 任何字母和数字
[[:space:]] 任何白字符
[[:upper:]] 任何大写字母
[[:lower:]] 任何小写字母
[[:punct:]] 任何标点符号
[[:xdigit:]] 任何16进制的数字,相当于[0-9a-fA-F]
7.3
确定重复出现
到现在为止,你已经知道如何去匹配一个字母或数字,但更多的情况下,可能要匹配一个单词或一组数字。一个单词有若干个字母组成,一组数字有若干个单数组成。跟在字符或字符簇后面的花括号({})用来确定前面的内容的重复出现的次数。
字符簇 含义
^[a-zA-Z_]$ 所有的字母和下划线
^[[:alpha:]]{3}$ 所有的3个字母的单词
^a$ 字母a
^a{4}$ aaaa
^a{2,4}$ aa,aaa或aaaa
^a{1,3}$ a,aa或aaa
^a{2,}$
包含多于两个a的字符串
^a{2,} 如:aardvark和aaab,但apple不行
a{2,}
如:baad和aaa,但Nantucket不行
"t{2} 两个制表符
.{2} 所有的两个字符
这些例子描述了花括号的三种不同的用法。一个数字,{x}的意思是“前面的字符或字符簇只出现x次”;一个数字加逗号,{x,}的意思是“前面的内容出现x或更多的次数”;两个用逗号分隔的数字,{x,y}表示“前面的内容至少出现x次,但不超过y次”。我们可以把模式扩展到更多的单词或数字:
^[a-zA-Z0-9_]{1,}$ //所有包含一个以上的字母、数字或下划线的字符串
^[0-9]{1,}$ //所有的正数
^"-{0,1}[0-9]{1,}$ //所有的整数
^"-{0,1}[0-9]{0,}".{0,1}[0-9]{0,}$ //所有的小数
最后一个例子不太好理解,是吗?这么看吧:与所有以一个可选的负号("-{0,1})开头(^)、跟着0个或更多的数字([0-9]{0,})、和一个可选的小数点(".{0,1})再跟上0个或多个数字([0-9]{0,}),并且没有其他任何东西($)。下面你将知道能够使用的更为简单的方法。
特殊字符"?"与{0,1}是相等的,它们都代表着:“0个或1个前面的内容”或“前面的内容是可选的”。所以刚才的例子可以简化为:
^"-?[0-9]{0,}".?[0-9]{0,}$
特殊字符"*"与{0,}是相等的,它们都代表着“0个或多个前面的内容”。最后,字符"+"与
{1,}是相等的,表示“1个或多个前面的内容”,所以上面的4个例子可以写成:
^[a-zA-Z0-9_]+$ //所有包含一个以上的字母、数字或下划线的字符串
^[0-9]+$ //所有的正数
^"-?[0-9]+$
//所有的整数
^"-?[0-9]*".?[0-9]*$ //所有的小数
当然这并不能从技术上降低正规表达式的复杂性,但可以使它们更容易阅读。
参考文献:
JScript 和 VBScript 正则表达式
微软MSDN上的例子(英文):
- Scanning for HREFS
- Provides an example that searches an input string and prints
out all the href="..." values and their locations in the string.
- Changing Date Formats
- Provides an example that replaces dates of the form mm/dd/yy
with dates of the form dd-mm-yy.
- Extracting URL Information
- Provides an example that extracts a protocol and port number
from a string containing a URL. For example,
"http://www.contoso.com:8080/letters/readme.html" returns "http:8080".
- Cleaning an Input String
- provides an example that strips invalid non-alphanumeric
characters from a string.
- Confirming Valid E-Mail Format
- Provides an example that you can use to verify that a string is
in valid e-mail format
|
正则表达式(regular
expression)对象包含一个正则表达式模式(pattern)。它具有用正则表达式模式去匹配或代替一个串(string)中特定字符(或字符集合)的属性(properties)和方法(methods)。
要为一个单独的正则表达式添加属性,可以使用正则表达式构造函数(constructor
function),无论何时被调用的预设置的正则表达式拥有静态的属性(the predefined RegExp object has static
properties that are set whenever any regular expression is used,
我不知道我翻得对不对,将原文列出,请自行翻译)。
- 创建:
一个文本格式或正则表达式构造函数
文本格式: /pattern/flags
正则表达式构造函数: new
RegExp("pattern"[,"flags"]);
- 参数说明:
pattern -- 一个正则表达式文本
flags -- 如果存在,将是以下值:
g: 全局匹配
i:
忽略大小写
gi: 以上组合
[注意] 文本格式的参数不用引号,而在用构造函数时的参数需要引号。如:/ab+c/i new
RegExp("ab+c","i")是实现一样的功能。在构造函数中,一些特殊字符需要进行转意(在特殊字符前加""")。如:re = new
RegExp("""w+")
正则表达式中的特殊字符
字符 |
含意 |
" |
做为转意,即通常在"""后面的字符不按原来意义解释,如/b/匹配字符"b",当b前面加了反斜杆后/"b/,转意为匹配一个单词的边界。
-或-
对正则表达式功能字符的还原,如"*"匹配它前面元字符0次或多次,/a*/将匹配a,aa,aaa,加了"""后,/a"*/将只匹配"a*"。
|
^ |
匹配一个输入或一行的开头,/^a/匹配"an A",而不匹配"An a" |
$ |
匹配一个输入或一行的结尾,/a$/匹配"An a",而不匹配"an A" |
* |
匹配前面元字符0次或多次,/ba*/将匹配b,ba,baa,baaa |
+ |
匹配前面元字符1次或多次,/ba*/将匹配ba,baa,baaa |
? |
匹配前面元字符0次或1次,/ba*/将匹配b,ba |
(x) |
匹配x保存x在名为$1...$9的变量中 |
x|y |
匹配x或y |
{n} |
精确匹配n次 |
{n,} |
匹配n次以上 |
{n,m} |
匹配n-m次 |
[xyz] |
字符集(character set),匹配这个集合中的任一一个字符(或元字符) |
[^xyz] |
不匹配这个集合中的任何一个字符 |
["b] |
匹配一个退格符 |
"b |
匹配一个单词的边界 |
"B |
匹配一个单词的非边界 |
"cX |
这儿,X是一个控制符,/"cM/匹配Ctrl-M |
"d |
匹配一个字数字符,/"d/ = /[0-9]/ |
"D |
匹配一个非字数字符,/"D/ = /[^0-9]/ |
"n |
匹配一个换行符 |
"r |
匹配一个回车符 |
"s |
匹配一个空白字符,包括"n,"r,"f,"t,"v等 |
"S |
匹配一个非空白字符,等于/[^"n"f"r"t"v]/ |
"t |
匹配一个制表符 |
"v |
匹配一个重直制表符 |
"w |
匹配一个可以组成单词的字符(alphanumeric,这是我的意译,含数字),包括下划线,如["w]匹配"$5.98"中的5,等于[a-zA-Z0-9]
|
"W |
匹配一个不可以组成单词的字符,如["W]匹配"$5.98"中的$,等于[^a-zA-Z0-9]。 |
|
说了这么多了,我们来看一些正则表达式的实际应用的例子:
E-mail地址验证:
function test_email(strEmail) {
var myReg =
/^[_a-z0-9]+@([_a-z0-9]+".)+[a-z0-9]{2,3}$/;
if(myReg.test(strEmail))
return true;
return false;
}
HTML代码的屏蔽
function
mask_HTMLCode(strInput) {
var myReg = /<("w+)>/;
return
strInput.replace(myReg, "<$1>");
}
正则表达式对象的属性及方法
预定义的正则表达式拥有有以下静态属性:input, multiline,
lastMatch, lastParen, leftContext,
rightContext和$1到$9。其中input和multiline可以预设置。其他属性的值在执行过exec或test方法后被根据不同条件赋以不同的值。许多属性同时拥有长和短(perl风格)的两个名字,并且,这两个名字指向同一个值。(JavaScript模拟perl的正则表达式)
正则表达式对象的属性
属性 |
含义 |
$1...$9 |
如果它(们)存在,是匹配到的子串 |
$_ |
参见input |
$* |
参见multiline |
$& |
参见lastMatch |
$+ |
参见lastParen |
$` |
参见leftContext |
$' |
参见rightContext |
constructor |
创建一个对象的一个特殊的函数原型 |
global |
是否在整个串中匹配(bool型) |
ignoreCase |
匹配时是否忽略大小写(bool型) |
input |
被匹配的串 |
lastIndex |
最后一次匹配的索引 |
lastParen |
最后一个括号括起来的子串 |
leftContext |
最近一次匹配以左的子串 |
multiline |
是否进行多行匹配(bool型) |
prototype |
允许附加属性给对象 |
rightContext |
最近一次匹配以右的子串 |
source |
正则表达式模式 |
lastIndex |
最后一次匹配的索引
|
|
正则表达式对象的方法
方法 |
含义 |
compile |
正则表达式比较 |
exec |
执行查找 |
test |
进行匹配 |
toSource |
返回特定对象的定义(literal representing),其值可用来创建一个新的对象。重载Object.toSource方法得到的。
|
toString |
返回特定对象的串。重载Object.toString方法得到的。 |
valueOf |
返回特定对象的原始值。重载Object.valueOf方法得到 |
|
例子
<script language = "JavaScript">
var myReg = /(w+)s(w+)/;
var
str = "John Smith";
var newstr = str.replace(myReg, "$2, $1");
document.write(newstr);
</script>
将输出"Smith, John"
〓简介〓
字符意义:对于字符,通常表示按字面意义,指出接着的字符为特殊字符,不作解释。
例如:/b/匹配字符'b',通过在b
前面加一个反斜杠,也就是/b/,则该字符变成特殊字符,表示匹配一个单词的分界线。或者:对于几个字符,通常说明是特殊的,指出紧接着的字符不是特殊的,而应该按字面解释。例如:*是一个特殊字符,匹配任意个字符(包括0个字符);例如:/a*/意味匹配0个或多个a。为了匹配字面上的*,在a前面加一个反斜杠;例如:/a*/匹配'a*'。
〓正文〓
字符
意义:对于字符,通常表示按字面意义,指出接着的字符为特殊字符,不作解释。
例如:/b/匹配字符'b',通过在b
前面加一个反斜杠,也就是/b/,则该字符变成特殊字符,表示
匹配一个单词的分界线。
或者:
对于几个字符,通常说明是特殊的,指出紧接着的字符不是特殊的,而应该按字面解释。
例如:*是一个特殊字符,匹配任意个字符(包括0个字符);例如:/a*/意味匹配0个或多个a。
为了匹配字面上的*,在a前面加一个反斜杠;例如:/a*/匹配'a*'。
字符^
意义:表示匹配的字符必须在最前边。
例如:/^A/不匹配"an A,"中的'A',但匹配"An A."中最前面的'A'。
字符$
意义:与^类似,匹配最末的字符。
例如:/t$/不匹配"eater"中的't',但匹配"eat"中的't'。
字符*
意义:匹配*前面的字符0次或n次。
例如:/bo*/匹配"A ghost booooed"中的'boooo'或"A bird
warbled"中的'b',但不匹配"A goat g
runted"中的任何字符。
字符+
意义:匹配+号前面的字符1次或n次。等价于{1,}。
例如:/a+/匹配"candy"中的'a'和"caaaaaaandy."中的所有'a'。
字符?
意义:匹配?前面的字符0次或1次。
例如:/e?le?/匹配"angel"中的'el'和"angle."中的'le'。
字符.
意义:(小数点)匹配除换行符外的所有单个的字符。
例如:/.n/匹配"nay, an apple is on the
tree"中的'an'和'on',但不匹配'nay'。
字符(x)
意义:匹配'x'并记录匹配的值。
例如:/(foo)/匹配和记录"foo
bar."中的'foo'。匹配子串能被结果数组中的素[1], ..., [n] 返
回,或被RegExp对象的属性$1, ..., $9返回。
字符x|y
意义:匹配'x'或者'y'。
例如:/green|red/匹配"green apple"中的'green'和"red
apple."中的'red'。
字符{n}
意义:这里的n是一个正整数。匹配前面的n个字符。
例如:/a{2}/不匹配"candy,"中的'a',但匹配"caandy,"
中的所有'a'和"caaandy."中前面的两个
'a'。
字符{n,}
意义:这里的n是一个正整数。匹配至少n个前面的字符。
例如:/a{2,}不匹配"candy"中的'a',但匹配"caandy"中的所有'a'和"caaaaaaandy."中的所有'a'
字符{n,m}
意义:这里的n和m都是正整数。匹配至少n个最多m个前面的字符。
例如:/a{1,3}/不匹配"cndy"中的任何字符,但匹配 "candy,"中的'a',"caandy," 中的前面两个
'a'和"caaaaaaandy"中前面的三个'a',注意:即使"caaaaaaandy" 中有很多个'a',但只匹配前面的三
个'a'即"aaa"。
字符[xyz]
意义:一字符列表,匹配列出中的任一字符。你可以通过连字符-指出一个字符范围。
例如:[abcd]跟[a-c]一样。它们匹配"brisket"中的'b'和"ache"中的'c'。
字符[^xyz]
意义:一字符补集,也就是说,它匹配除了列出的字符外的所有东西。 你可以使用连字符-指出一
字符范围。
例如:[^abc]和[^a-c]等价,它们最早匹配"brisket"中的'r'和"chop."中的'h'。
字符[b]
意义:匹配一个空格(不要与b混淆)
字符b
意义:匹配一个单词的分界线,比如一个空格(不要与[b]混淆)
例如:/bnw/匹配"noonday"中的'no',/wyb/匹配"possibly yesterday."中的'ly'。
字符B
意义:匹配一个单词的非分界线
例如:/wBn/匹配"noonday"中的'on',/yBw/匹配"possibly
yesterday."中的'ye'。
字符cX
意义:这里的X是一个控制字符。匹配一个字符串的控制字符。
例如:/cM/匹配一个字符串中的control-M。
字符d
意义:匹配一个数字,等价于[0-9]。
例如:/d/或/[0-9]/匹配"B2 is the suite
number."中的'2'。
字符D
意义:匹配任何的非数字,等价于[^0-9]。
例如:/D/或/[^0-9]/匹配"B2 is the suite
number."中的'B'。
字符f
意义:匹配一个表单符
字符n
意义:匹配一个换行符
字符r
意义:匹配一个回车符
字符s
意义:匹配一个单个white空格符,包括空格,tab,form feed,换行符,等价于[ fnrtv]。
例如:/sw*/匹配"foo bar."中的' bar'。
字符S
意义:匹配除white空格符以外的一个单个的字符,等价于[^ fnrtv]。
例如:/S/w*匹配"foo
bar."中的'foo'。
字符t
意义:匹配一个制表符
字符v
意义:匹配一个顶头制表符
字符w
意义:匹配所有的数字和字母以及下划线,等价于[A-Za-z0-9_]。
例如:/w/匹配"apple,"中的'a',"$5.28,"中的'5'和"3D."中的'3'。
字符W
意义:匹配除数字、字母外及下划线外的其它字符,等价于[^A-Za-z0-9_]。
例如:/W/或者/[^$A-Za-z0-9_]/匹配"50%."中的'%'。
字符n
意义:这里的n是一个正整数。匹配一个正则表达式的最后一个子串的n的值(计数左圆括号)。
例如:/apple(,)sorange1/匹配"apple, orange, cherry, peach."中的'apple, orange',下面
有一个更加完整的例子。
注意:如果左圆括号中的数字比n指定的数字还小,则n取下一行的八进制escape作为描述。
字符ooctal和xhex
意义:这里的ooctal是一个八进制的escape值,而xhex是一个十六进制的escape值,允许在一个正则表达式中嵌入ASCII码。
内存模型 (memory model)
内存模型描述的是程序中各变量(实例域、静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存取出变量这样的低层细节.
不同平台间的处理器架构将直接影响内存模型的结构.
在C或C++中, 可以利用不同操作平台下的内存模型来编写并发程序. 但是, 这带给开发人员的是, 更高的学习成本.
相比之下, java利用了自身虚拟机的优势, 使内存模型不束缚于具体的处理器架构, 真正实现了跨平台.
(针对hotspot jvm, jrockit等不同的jvm, 内存模型也会不相同)
内存模型的特征:
a, Visibility 可视性 (多核,多线程间数据的共享)
b, Ordering 有序性 (对内存进行的操作应该是有序的)
java 内存模型
(
java memory model
)
根据Java Language Specification中的说明, jvm系统中存在一个主内存(Main Memory或Java Heap Memory),Java中所有变量都储存在主存中,对于所有线程都是共享的。
每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。
其中, 工作内存里的变量, 在多核处理器下, 将大部分储存于处理器高速缓存中, 高速缓存在不经过内存时, 也是不可见的.
jmm怎么体现 可视性(Visibility) ?
在jmm中, 通过并发线程修改变量值, 必须将线程变量同步回主存后, 其他线程才能访问到.
jmm怎么体现 有序性(Ordering) ?
通过java提供的同步机制或volatile关键字, 来保证内存的访问顺序.
缓存一致性(cache coherency)
什么是缓存一致性?
它是一种管理多处理器系统的高速缓存区结构,其可以保证数据在高速缓存区到内存的传输中不会丢失或重复。(来自wikipedia)
举例理解:
假如有一个处理器有一个更新了的变量值位于其缓存中,但还没有被写入主内存,这样别的处理器就可能会看不到这个更新的值.
解决缓存一致性的方法?
a, 顺序一致性模型:
要求某处理器对所改变的变量值立即进行传播, 并确保该值被所有处理器接受后, 才能继续执行其他指令.
b, 释放一致性模型: (类似jmm cache coherency)
允许处理器将改变的变量值延迟到释放锁时才进行传播.
jmm缓存一致性模型 - "happens-before ordering(先行发生排序)"
一般情况下的示例程序:
x = 0;
y = 0;
i = 0;
j = 0;
// thread A
y = 1;
x = 1;
// thread B
i = x;
j = y;
在如上程序中, 如果线程A,B在无保障情况下运行, 那么i,j各会是什么值呢?
答案是, 不确定. (00,01,10,11都有可能出现)
这里没有使用java同步机制, 所以 jmm 有序性和可视性 都无法得到保障.
happens-before ordering(
先行发生排序)
如何避免这种情况?
排序原则已经做到:
a,
在程序顺序中,
线程中的每一个操作, 发生在当前操作后面将要出现的每一个操作之前.
b, 对象监视器的解锁发生在等待获取对象锁的线程之前.
c, 对volitile关键字修饰的变量写入操作, 发生在对该变量的读取之前.
d,
对一个线程的 Thread.start() 调用 发生在启动的线程中的所有操作之前.
e, 线程中的所有操作 发生在从这个线程的 Thread.join()成功返回的所有其他线程之前.
为了实现
happends-before ordering原则, java及jdk提供的工具:
a, synchronized关键字
b, volatile关键字
c, final变量
d, java.util.concurrent.locks包(since jdk 1.5)
e, java.util.concurrent.atmoic包(since jdk 1.5)
...
使用了happens-before ordering的例子:
(1) 获取对象监视器的锁(lock)
(2) 清空工作内存数据, 从主存复制变量到当前工作内存, 即同步数据 (read and load)
(3) 执行代码,改变共享变量值 (use and assign)
(4) 将工作内存数据刷回主存 (store and write)
(5) 释放对象监视器的锁 (unlock)
注意: 其中4,5两步是同时进行的.
这边最核心的就是第二步, 他同步了主内存,即前一个线程对变量改动的结果,可以被当前线程获知!(利用了happens-before ordering原则)
对比之前的例子
如果多个线程同时执行一段未经锁保护的代码段,很有可能某条线程已经改动了变量的值,但是其他线程却无法看到这个改动,依然在旧的变量值上进行运算,最终导致不可预料的运算结果。
经典j2ee设计模式Double-Checked Locking失效问题
双重检查锁定失效问题,一直是JMM无法避免的缺陷之一.了解DCL失效问题, 可以帮助我们深入JMM运行原理.
要展示DCL失效问题, 首先要理解一个重要概念- 延迟加载(lazy loading).
非单例的单线程延迟加载示例:
class Foo
{
private Resource res = null;
public Resource getResource()
{
// 普通的延迟加载
if (res == null)
res = new Resource();
return res;
}
}
非单例的
多线程延迟加载示例:
Class Foo
{
Private Resource res = null;
Public synchronized
Resource getResource()
{
// 获取实例操作使用同步方式, 性能不高
If (res == null) res = new Resource();
return res;
}
}
非单例的
DCL多线程延迟加载示例:
Class Foo
{
Private Resource res = null;
Public Resource getResource()
{
If (res == null)
{
//只有在第一次初始化时,才使用同步方式.
synchronized(this)
{
if(res == null)
{
res = new Resource();
}
}
}
return res;
}
}
Double-Checked Locking看起来是非常完美的。但是很遗憾,根据Java的语言规范,上面的代码是不可靠的。
出现上述问题, 最重要的2个原因如下:
1, 编译器优化了程序指令, 以加快cpu处理速度.
2, 多核cpu动态调整指令顺序, 以加快并行运算能力.
问题出现的顺序:
1, 线程A, 发现对象未实例化, 准备开始实例化
2, 由于编译器优化了程序指令, 允许对象在构造函数未调用完前, 将
共享变量的引用指向
部分构造的对象, 虽然对象未完全实例化, 但已经不为null了.
3, 线程B, 发现部分构造的对象已不是null, 则直接返回了该对象.
不过, 一些著名的开源框架, 包括jive,lenya等也都在使用DCL模式, 且未见一些极端异常.
说明, DCL失效问题的出现率还是比较低的.
接下来就是性能与稳定之间的选择了?
DCL的替代
Initialize-On-Demand
:
public class Foo {
// 似有静态内部类, 只有当有引用时, 该类才会被装载
private static class LazyFoo {
public static Foo foo = new Foo();
}
public static Foo getInstance() {
return LazyFoo.foo;
}
}
维基百科的DCL解释:
http://en.wikipedia.org/wiki/Double-checked_locking
DCL的完美解决方案:
http://www.theserverside.com/patterns/thread.tss?thread_id=39606
总结:
多线程编程, 针对有写操作的变量, 必须 保证其所有引用点与主存中数据一致(考虑采用同步或volatile)
.
Executor
提供了管理终止的方法,以及可为跟踪一个或多个异步任务执行状况而生成 Future
的方法。
可以关闭 ExecutorService,这将导致其停止接受新任务。关闭后,执行程序将最后终止,这时没有任务在执行,也没有任务在等待执行,并且无法提交新任务。
通过创建并返回一个可用于取消执行和/或等待完成的 Future
,方法 submit 扩展了基本方法 Executor.execute(java.lang.Runnable)
。方法 invokeAny 和 invokeAll 是批量执行的最常用形式,它们执行任务集合,然后等待至少一个,或全部任务完成(可使用 ExecutorCompletionService
类来编写这些方法的自定义变体)。
Executors
类提供了用于此包中所提供的执行程序服务的工厂方法。
用法示例
下面给出了一个网络服务的简单结构,这里线程池中的线程作为传入的请求。它使用了预先配置的
Executors.newFixedThreadPool(int)
工厂方法:
class NetworkService {
private final ServerSocket serverSocket;
private final ExecutorService pool;
public NetworkService(int port, int poolSize) throws IOException {
serverSocket = new ServerSocket(port);
pool = Executors.newFixedThreadPool(poolSize);
}
public void serve() {
try {
for (;;) {
pool.execute(new Handler(serverSocket.accept()));
}
} catch (IOException ex) {
pool.shutdown();
}
}
}
class Handler implements Runnable {
private final Socket socket;
Handler(Socket socket) { this.socket = socket; }
public void run() {
// read and service request
}
}
压缩不仅仅可以提高用户的下载速度,同时还可以加密代码,下面说下一个常用的js压缩方法:
首先使用dojo的工具shrinksafe(http://shrinksafe.dojotoolkit.org/)压缩一下,dojo的这个
工具会去掉注释,他的压缩不是简单的替换变量,而是利用了mozilla的一个工具,对js解析后才压缩,确保压缩后的代码不会出错。
dojo压缩后,并不会减少太多,下一步可以使用http://javascriptcompressor.com/这个站点进行更高层次的压缩,可惜只能登陆这个站点再压缩,只能将你的js代码复制的他的文本框,然后等他的压缩输出
经过这2步,你的js会变得既安全,文件又小
关于JSP页面中的pageEncoding和contentType两种属性的区别:
pageEncoding是jsp文件本身的编码
contentType的charset是指服务器发送给客户端时的内容编码
JSP要经过两次的“编码”,第一阶段会用pageEncoding,第二阶段会用utf-8至utf-8,第三阶段就是由Tomcat出来的网页,
用的是contentType。Phontol.com
第一阶段是jsp编译成.java,它会根据pageEncoding的设定读取jsp,结果是由指定的编码方案翻译成统一的UTF-8
JAVA源码(即.java),如果pageEncoding设定错了,或没有设定,出来的就是中文乱码。Phontol.com
第二阶段是由JAVAC的JAVA源码至java
byteCode的编译,不论JSP编写时候用的是什么编码方案,经过这个阶段的结果全部是UTF-8的encoding的java源码。Phontol.com
JAVAC用UTF-8的encoding读取java源码,编译成UTF-8
encoding的二进制码(即.class),这是JVM对常数字串在二进制码(java encoding)内表达的规范。Phontol.com
第三阶段是Tomcat(或其的application
container)载入和执行阶段二的来的JAVA二进制码,输出的结果,也就是在客户端见到的,这时隐藏在阶段一和阶段二的参数contentType就发挥了功效
contentType的設定.
pageEncoding 和contentType的预设都是 ISO8859-1. 而随便设定了其中一个,
另一个就跟着一样了(TOMCAT4.1.27是如此). 但这不是绝对的, 这要看各自JSPC的处理方式.
而pageEncoding不等于contentType, 更有利亚洲区的文字 CJKV系JSP网页的开发和展示, (例pageEncoding=GB2312
不等于 contentType=utf-8)。
在Tomcat中如果在jsp中设定了pageEncoding,则contentType也跟着设定成相同的编码了,但是在resion中就不是,resin中还会用默认的,这点通过查看编译后的类servlet java文件就可以看到这一点,而问题恰恰就出在这里,所以,在jsp中,如果是在resin下最好还是明确的单独设定这2个属性。
jsp文件不像.java,.java在被编译器读入的时候默认采用的是操作系统所设定的locale所对应的编码,比如中国大陆就是GBK,台湾就是BIG5或者MS950。Phontol.com而一般我们不管是在记事本还是在ue中写代码,如果没有经过特别转码的话,写出来的都是本地编码格式的内容。Phontol.com所以编译器采用的方法刚好可以让虚拟机得到正确的资料。Phontol.com
但是jsp文件不是这样,它没有这个默认转码过程,但是指定了pageEncoding就可以实现正确转码了。Phontol.com
举个例子:
<%@ page contentType="text/html;charset=utf-8" %>
|
大都会打印出乱码,因为输入的“你好”是gbk的,但是服务器是否正确抓到“你好”不得而知。Phontol.com
但是如果更改为
<%@ page contentType="text/html;charset=utf-8" pageEncoding="GBK"%>
|
这样就服务器一定会是正确抓到“你好”了。Phontol.com
首先,在linux上安装perl-Mail-Sendmail-0.79-1.0.rh9.rf.noarch.rpm
perl 代码如下:
#!/usr/bin/perl
use Mail::Sendmail;
$delay = 1;
$f_list="list.txt";
$line = 0;#skip the column title line
my $subject="xxx";
open(FILE,$f_list) || die "Can not open list file\n";
while(<FILE>){
chomp;
$line=$line+1;
next if($line==1);
($email,$passwd,$username,$yonghuming) = split(/,/);
%mail = (
from => 'xxx@xxx.com',
to => $email,
subject => $subject,
'content-type' => 'text/html; charset="gbk"',
);
$mail{body} = <<END_OF_BODY;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gbk">
<title>个人邮箱登陆</title>
<style type="text/css">
<!--
body {
margin-left: 0px;
margin-top: 0px;
margin-right: 0px;
margin-bottom: 0px;
}
-->
</style>
<link href="images/css.css" rel="stylesheet" type="text/css">
<style type="text/css">
<!--
.style1 {font-size: 13px}
.style3 {color: #0066CC}
.style4 {color: #FF0000}
-->
</style>
</head>
<body>
<table width="60%" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td height="10" valign="bottom"><hr width="100%" size="10" color="#3399FF">test</td>
</tr>
</table>
</body>
</html>
END_OF_BODY
sendmail(%mail) || print "Error: $Mail::Sendmail::error\n";
sleep($delay);
}
close(FILE);
list file 内容格式:
xx@163.com,xdf.com,xxx,xxx
在firefox3下Components.classes 是不允许直接调用的,需要加上如下那句粗体的语句才可以
<script>
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var prefs = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefBranch);
prefs.setBoolPref("dom.allow_scripts_to_close_windows", true);
</script>
在chomal.manifest里如下设定,注意黄色部分,很关键
content sample chrome/content/
xpcnativewrappers=no
overlay chrome://browser/content/browser.xul chrome://sample/content/sample.xul
调用方式:
window.content.document.getElementById('sssddd').onclick();
参考如下连接
http://developer.mozilla.org/En/Safely_accessing_content_DOM_from_chrome
xpcnativewrappers
http://developer.mozilla.org/en/Chrome_Registration
<style type="text/css" media="all">
div,img{margin: 0;padding: 0;border: 0;}
#content{width: 303px;height: 404px;background: #F63;color: #000;font: 12px Arial,Helvetica,sans-serif;position: relative;}
#content div{position: absolute;left: 0;bottom: 0;}
</style>
</head>
<body>
<div id="content">
<div>底端对齐 </div>
</div>
select max(a.num) A,max(b.num) B,max(c.num) C,tttt.name from tttt
left join (select * from tttt where abc='C') c on c.abc=tttt.abc and c.name=tttt.name
left join (select * from tttt where abc='B') b on b.abc=tttt.abc and b.name=tttt.name
left join (select * from tttt where abc='A') a on a.abc=tttt.abc and a.name=tttt.name
group by name
很多朋友在深入的接触 JAVA 语言后就会发现这样两个词:反射 (Reflection) 和内省 (Introspector) ,经常搞不清楚这到底是怎么回事,在什么场合下应用以及如何使用?今天把这二者放在一起介绍,因为它们二者是相辅相成的。
反射
相对而言,反射比内省更容易理解一点。用一句比较白的话来概括,反射就是让你可以通过名称来得到对象 ( 类,属性,方法 ) 的技术。例如我们可以通过类名来生成一个类的实例;知道了方法名,就可以调用这个方法;知道了属性名就可以访问这个属性的值。
还是写两个例子让大家更直观的了解反射的使用方法:
引用
//通过类名来构造一个类的实例
Class cls_str = Class.forName( "java.lang.String" );
// 上面这句很眼熟,因为使用过 JDBC 访问数据库的人都用过 J
Object str = cls_str.newInstance();
// 相当于 String str = new String();
//通过方法名来调用一个方法
String methodName = "length" ;
Method m = cls_str.getMethod(methodName, null );
System.out.println( "length is " + m.invoke(str, null ));
// 相当于 System.out.println(str.length());
上面的两个例子是比较常用方法。看到上面的例子就有人要发问了:为什么要这么麻烦呢?本来一条语句就完成的事情干吗要整这么复杂?没错,在上面的例子中确实没有必要这么麻烦。不过你想像这样一个应用程序,它支持动态的功能扩展,也就是说程序不重新启动但是可以自动加载新的功能,这个功能使用一个具体类来表示。首先我们必须为这些功能定义一个接口类,然后我们要求所有扩展的功能类必须实现我指定的接口,这个规定了应用程序和可扩展功能之间的接口规则,但是怎么动态加载呢?我们必须让应用程序知道要扩展的功能类的类名,比如是 test.Func1 ,当我们把这个类名 ( 字符串 ) 告诉应用程序后,它就可以使用我们第一个例子的方法来加载并启用新的功能。这就是类的反射,请问你有别的选择吗?
关于方法的反射建议大家看我的另外一篇文章《 利用 Turbine 的事件映射来扩展 Struts 的功能 》,地址是: http://www.javayou.com/article/CSDN/extend_struts.html 。这篇文章详细介绍了如果通过反射来扩展 Struts 框架的功能。
内省
内省是 Java 语言对 Bean 类属性、事件的一种缺省处理方法。例如类 A 中有属性 name, 那我们可以通过 getName,setName 来得到其值或者设置新的值。通过 getName/setName 来访问 name 属性,这就是默认的规则。 Java 中提供了一套 API 用来访问某个属性的 getter/setter 方法,通过这些 API 可以使你不需要了解这个规则(但你最好还是要搞清楚),这些 API 存放于包 java.beans 中。
一般的做法是通过类 Introspector 来获取某个对象的 BeanInfo 信息,然后通过 BeanInfo 来获取属性的描述器( PropertyDescriptor ),通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后我们就可以通过反射机制来调用这些方法。下面我们来看一个例子,这个例子把某个对象的所有属性名称和值都打印出来:
引用
/*
* Created on 2004-6-29
*/
package demo;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
/**
* 内省演示例子
* @author liudong
*/
public class IntrospectorDemo {
String name;
public static void main(String[] args) throws Exception{
IntrospectorDemo demo = new IntrospectorDemo();
demo.setName( "Winter Lau" );
// 如果不想把父类的属性也列出来的话,
// 那 getBeanInfo 的第二个参数填写父类的信息
BeanInfo bi = Introspector.getBeanInfo(demo.getClass(), Object. class );
PropertyDescriptor[] props = bi.getPropertyDescriptors();
for ( int i=0;i<props.length;i++){
System.out.println(props[i].getName()+ "=" +
props[i].getReadMethod().invoke(demo, null ));
}
}
public String getName() {
return name;
}
public void setName(String name) {
this .name = name;
}
}
Web 开发框架 Struts 中的 FormBean 就是通过内省机制来将表单中的数据映射到类的属性上,因此要求 FormBean 的每个属性要有 getter/setter 方法。但也并不总是这样,什么意思呢?就是说对一个 Bean 类来讲,我可以没有属性,但是只要有 getter/setter 方法中的其中一个,那么 Java 的内省机制就会认为存在一个属性,比如类中有方法 setMobile ,那么就认为存在一个 mobile 的属性,这样可以方便我们把 Bean 类通过一个接口来定义而不用去关心具体实现,不用去关心 Bean 中数据的存储。比如我们可以把所有的 getter/setter 方法放到接口里定义,但是真正数据的存取则是在具体类中去实现,这样可提高系统的扩展性。
总结
将 Java 的反射以及内省应用到程序设计中去可以大大的提供程序的智能化和可扩展性。有很多项目都是采取这两种技术来实现其核心功能,例如我们前面提到的 Struts ,还有用于处理 XML 文件的 Digester 项目,其实应该说几乎所有的项目都或多或少的采用这两种技术。在实际应用过程中二者要相互结合方能发挥真正的智能化以及高度可扩展性。
另外,以下是SUN的java doc 对
Introspector的解释:
- public class Introspector
- extends Object
The Introspector class provides a standard way for tools to learn about the properties, events, and methods supported by a target Java Bean.
For each of those three kinds of information, the Introspector will separately analyze the bean's class and superclasses looking for either explicit or implicit information and use that information to build a BeanInfo object that comprehensively describes the target bean.
For each class "Foo", explicit information may be available if there exists a corresponding "FooBeanInfo" class that provides a non-null value when queried for the information. We first look for the BeanInfo class by taking the full package-qualified name of the target bean class and appending "BeanInfo" to form a new class name. If this fails, then we take the final classname component of this name, and look for that class in each of the packages specified in the BeanInfo package search path.
Thus for a class such as "sun.xyz.OurButton" we would first look for a BeanInfo class called "sun.xyz.OurButtonBeanInfo" and if that failed we'd look in each package in the BeanInfo search path for an OurButtonBeanInfo class. With the default search path, this would mean looking for "sun.beans.infos.OurButtonBeanInfo".
If a class provides explicit BeanInfo about itself then we add that to the BeanInfo information we obtained from analyzing any derived classes, but we regard the explicit information as being definitive for the current class and its base classes, and do not proceed any further up the superclass chain.
If we don't find explicit BeanInfo on a class, we use low-level reflection to study the methods of the class and apply standard design patterns to identify property accessors, event sources, or public methods. We then proceed to analyze the class's superclass and add in the information from it (and possibly on up the superclass chain).
Because the Introspector caches BeanInfo classes for better performance, take care if you use it in an application that uses multiple class loaders. In general, when you destroy a ClassLoader
that has been used to introspect classes, you should use the Introspector.flushCaches
or Introspector.flushFromCaches
method to flush all of the introspected classes out of the cache.
For more information about introspection and design patterns, please consult the JavaBeans specification.
FileInputStream 和 FileReader(头ho晕的)
FileReader 会做编码转换,FileInputStream会忠实于原始文件数据。任何形式的Reader都会涉及编码。
BufferedInputStream和BufferedOutputStream
BufferedInputStream:
添加了功能,即缓冲输入和支持 mark 和 reset 方法的能力。创建 BufferedInputStream
时即创建了一个内部缓冲区数组。读取或跳过流中的各字节时,必要时可根据所包含的输入流再次填充该内部缓冲区,一次填充多个字节。mark
操作记录输入流中的某个点,reset 操作导致在从所包含的输入流中获取新的字节前,再次读取自最后一次 mark 操作以来所读取的所有字节。
BufferedOutputStream:该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入基础输出流中,而不必为每次字节写入调用基础系统。
BufferedReader和FileReader
BufferedReader :由Reader类扩展而来,提供通用的缓冲方式文本读取,而且提供了很实用的readLine,读取分行文本很适合,BufferedReader是针对Reader的,不直接针对文件,也不是只针对文件读取。
FileReader
是由java.io.InputStreamReade扩展来的,是针对文件读取的。实际使用时往往用 BufferedReader
bufferedreader = new BufferedReader(new
FileReader("test.conf"));先建立一个文件reader,再用BufferedReader读。
FileInputStream和Reader
FileInputStream:
扩展自java.io.InputStream,InputStream提供的是字节流的读取,而非文本读取,这是和Reader类的根本区别。用
Reader读取出来的是char数组或者String ,使用InputStream读取出来的是byte数组。
Reader:Reader
类及其子类提供的字符流的读取char(16位),InputStream及其子类提供字节流的读取byte(8位),所以FileReader类是将文
件按字符流的方式读取,FileInputStream则按字节流的方式读取文件,BufferedReader的作用是提供缓冲,
InputStreamReader可以将读如stream转换成字符流方式(即reader)是reader和stream之间的桥梁
BufferedInputStream和BufferedOutputStream的一个例子
import java.io.*;
public class BufferedStreamDemo...{
public static void main(String[] args)...{
try...{
byte[] data=new byte[1];
File srcFile=new File("BufferedStreamDemo.java");
File desFile=new File("BufferedStreamDemo.txt");
BufferedInputStream bufferedInputStream=new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(new FileOutputStream(desFile));
System.out.println("复制文件: "+srcFile.length()+"字节");
while(bufferedInputStream.read(data)!=-1)...{
bufferedOutputStream.write(data);
}
//将缓冲区中的数据全部写出
bufferedOutputStream.flush();
System.out.println("复制完成");
//显示输出BufferedStreamDemo.txt文件的内容
bufferedInputStream =new BufferedInputStream(new FileInputStream(new File("BufferedStreamDemo.txt")));
while(bufferedInputStream.read(data)!=-1)...{
String str=new String(data);
System.out.print(str);
}
bufferedInputStream.close();
bufferedOutputStream.close();
}catch(ArrayIndexOutOfBoundsException e)...{
System.out.println("using: java useFileStream src des");
e.printStackTrace();
}catch(IOException e)...{
e.printStackTrace();
}
}
}
select distinct item.reportoid, item.lineoid, item.accountoid, sun.amount, mon.amount, tue.amount, wes.amount, thur.amount, fri.amount, sat.amount
from expenseitem item
left join (select reportoid, accountoid, lineoid, amount, itemDate from expenseitem
where itemDate = '2007-11-04' ) sun
on item.reportoid = sun.reportoid and
item.accountoid = sun.accountoid and
item.lineoid = sun.lineoid and
item.itemDate = sun.itemDate
left join (select reportoid, accountoid, lineoid, amount, itemDate from expenseitem
where itemDate = adddate('2007-11-04', 1) ) mon
on item.reportoid = mon.reportoid and
item.accountoid = mon.accountoid and
item.lineoid = mon.lineoid and
item.itemDate = mon.itemDate
left join (select reportoid, accountoid, lineoid,amount, itemDate from expenseitem
where itemDate = adddate('2007-11-04', 2)) tue
on item.reportoid = tue.reportoid and
item.accountoid = tue.accountoid and
item.lineoid = tue.lineoid and
item.itemDate = tue.itemDate
left join (select reportoid, accountoid, lineoid,amount, itemDate from expenseitem
where itemDate = adddate('2007-11-04', 3) ) wes
on item.reportoid = wes.reportoid and
item.accountoid = wes.accountoid and
item.lineoid = wes.lineoid and
item.itemDate = wes.itemDate
left join (select reportoid, accountoid, lineoid,amount, itemDate from expenseitem
where itemDate = adddate('2007-11-04', 4) ) thur
on item.reportoid = thur.reportoid and
item.accountoid = thur.accountoid and
item.lineoid = thur.lineoid and
item.itemDate = thur.itemDate
left join (select reportoid, accountoid, lineoid,amount, itemDate from expenseitem
where itemDate = adddate('2007-11-04', 5) ) fri
on item.reportoid = fri.reportoid and
item.accountoid = fri.accountoid and
item.lineoid = fri.lineoid and
item.itemDate = fri.itemDate
left join (select reportoid, accountoid, lineoid,amount, itemDate from expenseitem
where itemDate = adddate('2007-11-04', 6) ) sat
on item.reportoid = sat.reportoid and
item.accountoid = sat.accountoid and
item.lineoid = sat.lineoid and
item.itemDate = sat.itemDate
where item.reportoid = 3712
order by reportoid, accountoid;
SELECT REVERSE('abc') AS Expr1
SELECT ascii('c') AS Expr1 取asc码
select DATE_ADD(date('2008-01-01'),INTERVAL days DAY) days from (select 0 days union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 10 union select 11 union select 12 union select 13 union select 14 union select 15 union select 16 union select 17 union select 18 union select 19 union select 20 union select 21 union select 22 union select 23 union select 24 union select 25 union select 26 union select 27 union select 28 union select 29 union select 30 union select 31) as b
http://www.tutorialspoint.com/wsdl/index.htm
http://www.tutorialspoint.com/
通过使用某种协议进行通信来完成分布式事务,被称为
两段式提交。从名字上看,您可能已经知道有两个阶段:
- 第一个阶段,即预提交:
- 事务协调器给每个事务管理器发送准备操作的信号。
- 事务管理器将操作(通常是数据更新)步骤(或细节)写入事务日志。如果失败,事务管理器使用这些步骤重复操作。
- 事务管理器本地创建事务并通知资源管理器对资源(例如,数据库或消息服务器)执行操作。
- 资源管理器执行操作并向事务管理器报告成功(准备提交信号)或失败(准备回滚)。
- 资源管理器等待事务管理器进一步的指令。
- 事务管理器向事务协调器报告成功或失败。
- 第二阶段,即提交阶段:在第二阶段中,第一阶段的结果将传送给所有事务管理器。如果任何事务管理器报告失败,所有的事务参与者都必须回滚。
- 事务协调器让所有事务管理器提交(或回滚)。
- 所有事务管理器将提交或回滚信息传递给其资源管理器。
- 资源管理器将成功或失败提示返回给事务管理器。
- 事务管理器向事务协调器报告成功或失败。
【IT168 技术文档】很多人对二级缓存都不太了解,或者是有错误的认识,我一直想写一篇文章介绍一下hibernate的二级缓存的,今天终于忍不住了。
我的经验主要来自hibernate2.1版本,基本原理和3.0、3.1是一样的,请原谅我的顽固不化。
hibernate的session提供了一级缓存,每个session,对同一个id进行两次load,不会发送两条sql给数据库,但是session关闭的时候,一级缓存就失效了。
二级缓存是SessionFactory级别的全局缓存,它底下可以使用不同的缓存类库,比如ehcache、oscache等,需要设置hibernate.cache.provider_class,我们这里用ehcache,在2.1中就是
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider
如果使用查询缓存,加上
hibernate.cache.use_query_cache=true
缓存可以简单的看成一个Map,通过key在缓存里面找value。
Class的缓存
对于一条记录,也就是一个PO来说,是根据ID来找的,缓存的key就是ID,value是POJO。无论list,load还是
iterate,只要读出一个对象,都会填充缓存。但是list不会使用缓存,而iterate会先取数据库select
id出来,然后一个id一个id的load,如果在缓存里面有,就从缓存取,没有的话就去数据库load。假设是读写缓存,需要设置:
<cache usage="read-write"/>
如果你使用的二级缓存实现是ehcache的话,需要配置ehcache.xml
<cache
name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false"
timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true"
/>
其中eternal表示缓存是不是永远不超时,timeToLiveSeconds是缓存中每个元素(这里也就是一个POJO)的超时时间,如果
eternal="false",超过指定的时间,这个元素就被移走了。timeToIdleSeconds是发呆时间,是可选的。当往缓存里面put
的元素超过500个时,如果overflowToDisk="true",就会把缓存中的部分数据保存在硬盘上的临时文件里面。
每个需要缓存的class都要这样配置。如果你没有配置,hibernate会在启动的时候警告你,然后使用defaultCache的配置,这样多个class会共享一个配置。
当某个ID通过hibernate修改时,hibernate会知道,于是移除缓存。
这样大家可能会想,同样的查询条件,第一次先list,第二次再iterate,就可以使用到缓存了。实际上这是很难的,因为你无法判断什么时候是第一
次,而且每次查询的条件通常是不一样的,假如数据库里面有100条记录,id从1到100,第一次list的时候出了前50个id,第二次
iterate的时候却查询到30至70号id,那么30-50是从缓存里面取的,51到70是从数据库取的,共发送1+20条sql。所以我一直认为
iterate没有什么用,总是会有1+N的问题。
(题外话:有说法说大型查询用list会把整个结果集装入内存,很慢,而iterate只select
id比较好,但是大型查询总是要分页查的,谁也不会真的把整个结果集装进来,假如一页20条的话,iterate共需要执行21条语句,list虽然选择
若干字段,比iterate第一条select
id语句慢一些,但只有一条语句,不装入整个结果集hibernate还会根据数据库方言做优化,比如使用mysql的limit,整体看来应该还是
list快。)
如果想要对list或者iterate查询的结果缓存,就要用到查询缓存了
一个b好的介绍w3c的网站。
http://www.w3school.com.cn
http://webservices.ctocio.com.cn/wsjavtec/62/7690562.shtml
通常,你需要获得当前日期和计算一些其他的日期,例如,你的程序可能需要判断一个月的第一天或者最后一天。你们大部分人大概都知道怎样把日期进行分割
(年、月、日等),然后仅仅用分割出来的年、月、日等放在几个函数中计算出自己所需要的日期!在这篇文 章里,我将告诉你如何使用DATEADD和
DATEDIFF函数来计算出在你的程序中可能你要用到的一些不同日期。
在使用本文中的例子之前,你必须注意以下的问题。大部
分可能不是所有例子在不同的机器上执行的结果可能不一样,这完全由哪一天是一个星期的第一天这个设置决定。第一天(DATEFIRST)设定决定了你的系
统使用哪一天作为一周的第一天。所有以下的例 子都是以星期天作为一周的第一天来建立,也就是第一天设置为7。假如你的第一天设置不一样,你可能需要调整
这些例子,使它和不同的第一天设置相符合。你可以通过@@DATEFIRST函数来检查第一天设置。
为了理解这些例子,
我们先复习一下DATEDIFF和DATEADD函数。DATEDIFF函数计算两个日期之间的小时、天、周、月、年等时间间隔总数。DATEADD函数
计算一个日期通过给时间间隔加减来获得一个新的日期。要了解更多的DATEDI FF和DATEADD函数以及时间间隔可以阅读微软联机帮助。
使用DATEDIFF和DATEADD函数来计算日期,和本来从当前日期转换到你需要的日期的考虑方法有点不同。你必须从时间间隔这个方面来考虑。比
如,从当前日期到你要得到的日期之间有多少时间间隔,或者,从今天到某一天(比如1900-1-1)之间有多少时间间隔,等等。理解怎样着眼于时间间隔有
助于你轻松的理解我的不同的日期计算例子。
一个月的第一天
第一个例子,我将告诉你如何从当前日期去这个月的最后一天。请注意:这个例子以及这篇文章中的其他例子都将只使用DATEDIFF和DATEADD函数来计算我们想要的日期。每一个例子都将通过计算但前的时间间隔,然后进行加减来得到想要计算的日期。
这是计算一个月第一天的SQL 脚本:
SELECT DATEADD(mm, DATEDIFF(mm,0,getdate()), 0)
我们把这个语句分开来看看它是如何工作的。最核心的函数是getdate(),大部分人都知道这个是返回当前的日期和时间的函数。下一个执行的函数
DATEDIFF(mm,0,getdate())是计算当前日期和“1900-01-01 00:00:00.000”这个日期之间的月数。记住:时期
和时间变量和毫秒一样是从“1900-01-01 00:00:00.000”开始计算的。这就是为什么你可以在DATEDIFF函数中指定第一个时间表
达式为“0”。下一个函数是DATEADD,增加当前日期到“1900-01-01”的月数。通过增加预定义的日期“1900-01-01”和当前日期的
月数,我们可以获得这个月的第一天。另外,计算出来的日期的时间部分将会是“00:00:00.000”。
这个计算的技巧是先计算当前日期到“1900-01-01”的时间间隔数,然后把它加到“1900-01-01”上来获得特殊的日期,这个技巧可以用来计算很多不同的日期。下一个例子也是用这个技巧从当前日期来产生不同的日期。
本周的星期一
这里我是用周(wk)的时间间隔来计算哪一天是本周的星期一。
SELECT DATEADD(wk, DATEDIFF(wk,0,getdate()), 0)
一年的第一天
现在用年(yy)的时间间隔来显示这一年的第一天。
SELECT DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)
季度的第一天
假如你要计算这个季度的第一天,这个例子告诉你该如何做。
SELECT DATEADD(qq, DATEDIFF(qq,0,getdate()), 0)
当天的半夜
曾经需要通过getdate()函数为了返回时间值截掉时间部分,就会考虑到当前日期是不是在半夜。假如这样,这个例子使用DATEDIFF和DATEADD函数来获得半夜的时间点。
SELECT DATEADD(dd, DATEDIFF(dd,0,getdate()), 0)
深入DATEDIFF和DATEADD函数计算
你可以明白,通过使用简单的DATEDIFF和DATEADD函数计算,你可以发现很多不同的可能有意义的日期。
目前为止的所有例子只是仅仅计算当前的时间和“1900-01-01”之间的时间间隔数量,然后把它加到“1900-01-01”的时间间隔上来计算出
日期。假定你修改时间间隔的数量,或者使用不同的时间间隔来调用DATEADD函数,或者减去时间间隔而不是增加,那么通过这些小的调整你可以发现和多不
同的日期。
这里有四个例子使用另外一个DATEADD函数来计算最后一天来分别替换DATEADD函数前后两个时间间隔。
上个月的最后一天
这是一个计算上个月最后一天的例子。它通过从一个月的最后一天这个例子上减去3毫秒来获得。有一点要记住,在Sql Server中时间是精确到3毫秒。这就是为什么我需要减去3毫秒来获得我要的日期和时间。
SELECT dateadd(ms,-3,DATEADD(mm, DATEDIFF(mm,0,getdate()), 0))
计算出来的日期的时间部分包含了一个Sql Server可以记录的一天的最后时刻(“23:59:59:997”)的时间。
去年的最后一天
连接上面的例子,为了要得到去年的最后一天,你需要在今年的第一天上减去3毫秒。
SELECT dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0))
本月的最后一天
现在,为了获得本月的最后一天,我需要稍微修改一下获得上个月的最后一天的语句。修改需要给用DATEDIFF比较当前日期和“1900-01-01”
返回的时间间隔上加1。通过加1个月,我计算出下个月的第一天,然后减去3毫秒,这样就计算出了这个月的最后一天。这是计算本月最后一天的SQL脚本。
SELECT dateadd(ms,-3,DATEADD(mm, DATEDIFF(m,0,getdate())+1, 0))
本年的最后一天
你现在应该掌握这个的做法,这是计算本年最后一天脚本
SELECT dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate())+1, 0))。
本月的第一个星期一
好了,现在是最后一个例子。这里我要计算这个月的第一个星期一。这是计算的脚本。
select DATEADD(wk, DATEDIFF(wk,0,
dateadd(dd,6-datepart(day,getdate()),getdate())
), 0)
在这个例子里,我使用了“本周的星期一”的脚本,并作了一点点修改。修改的部分是把原来脚本中“getdate()”部分替换成计算本月的第6天,在计算中用本月的第6天来替换当前日期使得计算可以获得这个月的第一个星期一。
总结
我希望这些例子可以在你用DATEADD和DATEDIFF函数计算日期时给你一点启发。通过使用这个计算日期的时间间隔的数学方法,我发现为了显示两
个日期之间间隔的有用历法是有价值的。注意,这只是计算出这些日期的一种方法。要牢记,还有很多方法 可以得到相同的计算结果。假如你有其他的方法,那很
不错,要是你没有,我希望这些例子可以给你一些启发,当你要用DATEADD和DATEDIFF函数计算你程序可能要用到的日期时。
附录,其他日期处理方法
1)去掉时分秒
declare @ datetime
set @ = getdate() --’2003-7-1 10:00:00’
SELECT @,DATEADD(day, DATEDIFF(day,0,@), 0)
2)显示星期几
select datename(weekday,getdate())
3)如何取得某个月的天数
declare @m int
set @m=2 --月份
select datediff(day,’2003-’+cast(@m as varchar)+’-15’ ,’2003-’+cast(@m+1 as varchar)+’-15’)
另外,取得本月天数
select datediff(day,cast(month(GetDate()) as varchar)+’-’+cast(month(GetDate()) as varchar)+’-15’ ,cast(month(GetDate()) as varchar)+’-’+cast(month(GetDate())+1 as varchar)+’-15’)
或者使用计算本月的最后一天的脚本,然后用DAY函数区最后一天
SELECT Day(dateadd(ms,-3,DATEADD(mm, DATEDIFF(m,0,getdate())+1, 0)))
4)判断是否闰年:
SELECT case day(dateadd(mm, 2, dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)))) when 28 then ’平年’ else ’闰年’ end
或者
select case datediff(day,datename(year,getdate())+’-02-01’,dateadd(mm,1,datename(year,getdate())+’-02-01’))
when 28 then ’平年’ else ’闰年’ end
5)一个季度多少天
declare @m tinyint,@time smalldatetime
select @m=month(getdate())
select @m=case when @m between 1 and 3 then 1
when @m between 4 and 6 then 4
when @m between 7 and 9 then 7
else 10 end
select @time=datename(year,getdate())+’-’+convert(varchar(10),@m)+’-01’
select datediff(day,@time,dateadd(mm,3,@time))
The load-on-startup element indicates that this servlet should be loaded (instantiated and have its init() called) on the startup of the web application. The optional contents of these element must be an integer indicating the order in which the servlet should be loaded. If the value is a negative integer, or the element is not present, the container is free to load the servlet whenever it chooses. If the value is a positive integer or 0, the container must load and initialize the servlet as the application is deployed.
The container must guarantee that servlets marked with lower integers
are loaded before servlets marked with higher integers. The container
may choose the order of loading of servlets with the same
load-on-start-up value.
SOA现在正热得"烫手"。
对于SOA,目前我听到有两种说法:一种讲它是"颠覆性的革命架构",一种是"谨慎观望"。但无疑,SOA最近几年发展得非常快,各主要软件厂商纷纷高调跟进,关于SOA的报道可以说是不绝于耳。对"SOA热",程序员们有的兴奋和期待,有的则感到困惑,最近我在金蝶中间件于广州、上海等城市举行的"Java俱乐部"上和程序员们交流时,他们或是以一种朝圣者的表情说:"以前面向对象的技术过时了,SOA时代来了",或者一再恳切地追问我:"SOA到底是什么?作用是什么?"
那么,SOA是什么?到底能解决什么问题、解决得怎样?我们和客户都准备好了吗?我给出的答案是"Just Processing,SOA-现在进行中"。
SOA到底是什么?
SOA(Service-Oriented Architecture)的定义是面向服务的架构,就是说将软件按照功能设计成一个个服务,这些服务用标准的方式定义接口、并通过标准的协议进行调用。SOA所定义的接口和调用方式是独立于编程语言和运行平台的,广义上讲SOA可以基于不同的底层技术实现,比如CORBA和Web Services。但CORBA由于过于复杂和臃肿已很少使用,所以目前所说的SOA绝大多数是基于Web Services技术实现。在Web Services的实现方式下,SOA服务的接口用XML进行定义。
在SOA架构下,软件开发从业务流程分析开始,使用组件化业务建模的方法识别和分析各种业务模型,将各种实践融入其中,在这个基础上建立用例,用例直接产生BPEL,这些BPEL则可以被融入一个服务整合框架中,其描述了各种服务的信息,从而把ESB上的各个模块统一起来,形成一个巨大的服务仓。
这样,SOA甚至是所有软件人员的一个梦:将中间层再进行抽离,在中间层作一个跨技术架构的元数据和业务逻辑,使之成为跨技术架构的、可长期继承、并不断积累的企业业务库和最宝贵的信息资产,也就是面向服务的组件库,而且这个服务组件库也可以被其它企业复用,且不依赖于任何一种技术架构。夸张一点说,如果所有软件企业都使用SOA架构,那么世界软件业将会发生彻底的改变。显然,这样一个框架不是一种产品,也不仅仅是一种技术,而是一种解决问题的方法论。
SOA可能应用的两个场景及现有问题
那么,SOA要解决的问题是什么?我认为,从技术本质上讲,SOA可能应用于两个场景:第一种是业务互通互联;第二种是封闭交易系统,即将元数据和业务逻辑抽离,形成可复用。举个例子,在第一种场景中,当不同企业之间的业务需要相互调用,这时就可能采用SOA技术;在第二种场景中,在企业内部需要将系统进行迁移时,利用SOA技术定义的原有数据和业务流程,可以很快完成。
无疑,SOA是一个伟大的思想,它试图定义一个大家(各种软件厂商)都"认"的、都"遵循"的法则,大家都使用这样的方法来进行互联互通,从而实现无界限的联通,以及服务组件库的继承和复用,解放无效和重复劳动。打一个不那么恰当的比喻,就像人类的语言一样。SOA或许就像《圣经》中那个著名的"通天塔"的故事:人们用同一种语言交流产生的威力是如此之大,以至于他们在巴比伦几乎要修成一个"通天塔",直达上帝所在的天庭。
但是,在SOA应用的两个场景中,现存的问题同样也是明显的:
第一种场景:业务互联互通,就是应用系统互联。业务互联,与其说是技术问题,不如讲是业务问题,例如ERP、CRM的异步整合,数据层面整合都不能很好将两个系统整合,SOA仅仅是一种实现工具之一,整合效果并不会好不到那里去。我们可以说,在没有其他选项之前,SOA是一种最"不坏"的方式,但它并不能解决所有的问题,实际上EAI的牵涉面很广,而我们知道,有些问题并不是单纯靠技术就能解决的。
第二种场景:封闭交易系统,缺点是性能慢,而且基于Web Services的交易没有形成明确的规范。使用XML作信息交互比较慢是大家都承认的,性能问题将对SOA的发展造在一定的阻力。同时SOA规范本身没有完善,比如Transaction规范还在不断完善,而且Web Service多年来收效甚微。总的来说,SOA现在还处在一个发展阶段,很多标准还在制定,不同厂商间还存在不兼容的现象,因此SOA还不能说已经是一个成熟的技术,还需要时间的检验,还在"进行中"。当然,金蝶中间件作为JCP组织成员,也会推动SOA规范在J2EE平台上的实现。
中国用户的现实选择之惑
在憧憬SOA技术可能带来的前景之余,我们不得不回过头来冷静地说:SOA和我们大家的共同客户――中国企业还有距离。
中国信息化进程与欧美不同,大量的基础业务系统还没建立起来,整合需求并不如想象的那么大。从我们对客户的了解,发现很少有客户有SOA的需求。简单地总结就是,互通无基础,以新建系统为主,需求并不强烈。而欧美市场大量业务系统已建立起来需要整合,从这个角度讲,SOA是适用于他们的。同时,在成功案例极少的前提下,SOA还处于培育期,新建封闭交易系统使用SOA技术还是有一定风险的。
一项新技术需要市场的消化,大型企业出于保护企业投资,不会轻易地转移到新的技术平台;而即使像J2EE这样成熟的技术经过了这么多年的发展,也不敢说占有统治地位的市场份额。SOA还需要整个IT界的用户和供应商共同促进。
中国信息化需要什么样的技术架构、能够接受什么样的成本价位?这不仅仅是我们的客户需要考虑,我们软件厂商要比客户考虑得更清楚、更进一步。在这个充满变数的激烈竞争市场,只有冷静务实才能生存、发展。
From:http://blog.csdn.net/Apusicyuan/archive/2007/03/16/1531424.aspx
解析SOA十大设计原则 公共接口要明确界限
作者: 佚名, 出处:CSDN, 责任编辑: 包春林,
2008-04-23 05:00
日前国外网站报道介绍了面向服务架构(SOA)的基本原则,提出了公共接口与内部实现要有明确界限等原则。虽然这些原则并不是绝对的真理,但可作为一个应用开发参考。
一、明确的边界
通过跨越定义明确的边界进行显式消息传递,服务得以彼此交互。有时候,跨越服务边界可能要耗费很大的成本,这要视地理、信任或执行因素而定。边界是指服务的公共接口与其内部专用实现之间的界线。服务的边界通过 WSDL 发布,可能包括说明特定服务之期望的声明。
二、服务共享和约和架构,不是类
服务交互应当只以服务的策略、架构和基于合约的行为为基础。服务的合约通常使用 WSDL 定义,而服务聚合的合约则可以使用 BPEL 定义(进而,对聚合的每个服务使用 WSDL)。服务使用者将依靠服务的合约来调用服务及与服务交互。鉴于这种依赖性,服务合约必须长期保持稳定。在利用 XML 架构 (xsd:any) 和 SOAP 处理模型(可选标头)的可扩展性的同时,合约的设计应尽可能明确。
三、策略驱动
尽管它往往被认为是最不为人所了解的原则,但对于实现灵活的 Web 服务,它或许是最有力的。单纯依靠 WSDL 无法交流某些业务交互要求。可以使用策略表达式将结构兼容性(交流的内容)与语义兼容性(如何交流消息或者将消息交流给谁)分隔开来。
四、自治
服务是独立进行部署、版本控制和管理的实体。开发人员应避免对服务边界之间的空间进行假设,因为此空间比边界本身更容易改变。
五、采用可传输的协议格式,而不是API
通常,服务提供商基于某种传输协议(例如HTTP)提供服务,而服务消费者只能通过另一种不同的协议(比如MQ)通信。因此,也许需要在服务提供商与消费者之间建立一座异步起动同步运行的连接桥梁,超越HTTP和Java Messaging Service消息服务(JMS)等协议.从技术角度讲,Java Messaging Service消息服务(JMS)并不是一种传输协议,而是一组供应商中立(vendor-neutral)的通信APIs。
六、面向文档
消息被构造为“纯文本的”XML文档(换句话说,数据的格式只对XML有意义)。 消息通常用于传输业务文档,比如购买订单、发票和提单。这种交互类型与同步消息排队系统的兼容性很好,比如MQ Series、MSMQ、JMS、TIBCO、IMS等等。
七、松耦合
服务之间要求最小的依赖性,只要求它们之间能够相互知晓。
八、符合标准
当通过Web的服务实现时,最原始的(基本的)面向服务的架构(SOA)的模型仅仅提供了很低程度上的关于可靠性、安全性以及事务管理的标准化机制。第二代的技术条件和框架,如WS-ReliableMessaging规范、 WS-Security规范和WS-Coordination规范 (与WS-AtomicTransaction规范和WS-BusinessActivity规范相联系),它们试图以工业标准的方式定位存在的缺陷。
九、独立软件供应商
向SOA的转变正在深刻改变了经济现实。客户们会期待更合理的费用以及不必重新进行投资就能改进业务的能力。因此,独立软件供应商没有选择,只能使自己的业务更加灵活,以期让自己的客户也变得同样灵活。于是,面向服务不仅是简单的在现有的、紧耦合的、复杂的、不灵活的以及非组件化的业务功能上添加基于标准的接口。更重要的是,为了兑现SOA的承诺,独立软件供应商必须改变他们构建、打包、销售、交付、管理和支持自身产品的方式。
十、元数据驱动
开发元数据本身并不是元数据驱动应用程序的本意。使用元数据来驱动服务在系统边界的传播是一个更为正确的方法。
一个事务处理的属性有:Required,RequiresNew,Mandatory,NotSupported,Supports,Never.
1、Required:当客户端运行一个事务处理并调用EJB的一个方法,这个方法执行客户端的事务处理;当客户端没有启动一个事务处理,则EJB容器在执行这个方法之前启动一个新的事务处理.
2、RequiresNew:当客户端运行一个事务处理并调用EJB的一个方法时,容器管理器做如下操作:
(1) 悬挂客户端的事务处理;
(2) 开始一个新的事务处理;
(3) 调用方法;
(4) 当方法结束,恢复客户端的事物处理.
当客户端没有启动一个事务处理,容器管理器在执行这个方法之前启动一个新的事务处理.
3、Mandatory: 当客户端运行一个事务处理并调用EJB的一个方法,这个方法在客户端的事务处理范围内被执行; 当客户端没有启动一个事务处理,容器管理器将会抛错(TransactionRequiredException);
4、NotSupported: 当客户端运行一个事务处理并调用EJB的一个方法,容器管理器在调用方法之前终止客户端的事务处理,当方法执行完,再恢复客户端的事务处理; 当客户端没有启动一个事务处理,容器管理器在调用方法时不启动事务处理.
5、Supports: 当客户端运行一个事务处理并调用EJB的一个方法,在运行方法时执行客户端的事务处理; 当客户端没有启动一个事务处理,容器管理器在调用方法时不启动事务处理.
6、Never: 当客户端运行一个事务处理并调用EJB的一个方法,容器管理器将抛出一个错误(RemoteException); 当客户端没有启动一个事务处理,容器管理器在调用方法时不启动事务处理.
在jbuilder中,缺省是Required;
第一个ejb可以是 Required,这个ejb调用的那个ejb方法如果想在一个
事务上下文中,我觉得可能采用Mandatory,方式比较好。如果它们不在一个事务上下文中,就会抛错(TransactionRequiredException),是一个上下文,就没有问题
几乎每个做过Web开发的人都问过,到底元素的ID和Name有什么区别阿?为什么有了ID还要有Name呢?而同样我们也可以得到最classical的答案:ID就像是一个人的身份证号码,而Name就像是他的名字,ID显然是唯一的,而Name是可以重复的。
上周我也遇到了ID和Name的问题,在页面里输入了一个input type="hidden",只写了一个ID='SliceInfo',赋值后submit,在后台用Request.Params["SliceInfo"]却怎么也去不到值。后来恍然大悟因该用Name来标示,于是在input里加了个Name='SliceInfo',就一切ok了。
第一段里对于ID和Name的解答说的太笼统了,当然那个解释对于ID来说是完全对的,它就是Client端HTML元素的Identity。而Name其实要复杂的多,因为Name有很多种的用途,所以它并不能完全由ID来代替,从而将其取消掉。
具体用途有:
用途1: 作为可与服务器交互数据的HTML元素的服务器端的标示,比如input、select、textarea、和button等。我们可以在服务器端根据其Name通过Request.Params取得元素提交的值。
用途2: HTML元素Input type='radio'分组,我们知道radio button控件在同一个分组类,check操作是mutex的,同一时间只能选中一个radio,这个分组就是根据相同的Name属性来实现的。
用途3: 建立页面中的锚点,我们知道link是获得一个页面超级链接,如果不用href属性,而改用Name,如:,我们就获得了一个页面锚点。
用途4: 作为对象的Identity,如Applet、Object、Embed等元素。比如在Applet对象实例中,我们将使用其Name来引用该对象。
用途5: 在IMG元素和MAP元素之间关联的时候,如果要定义IMG的热点区域,需要使用其属性usemap,使usemap="#name"(被关联的MAP元素的Name)。
用途6: 某些特定元素的属性,如attribute,和param。例如为Object定义参数
显然这些用途都不是能简单的使用ID来代替掉的,所以HTML元素的ID和Name的却别并不是身份证号码和姓名这样的区别,它们更本就是不同作用的东西。
当然HTML元素的Name属性在页面中也可以起那么一点ID的作用,因为在DHTML对象树中,我们可以使用document.getElementsByName来获取一个包含页面中所有指定Name元素的对象数组。
在这里顺便说一下,要是页面中有n(n>1)个HTML元素的ID都相同了怎么办?在DHTML对象中怎么引用他们呢?如果我们使用ASPX页面,这样的情况是不容易发生的,因为aspnet进程在处理aspx页面时根本就不允许有ID非唯一,这是页面会被抛出异常而不能被正常的render。要是不是动态页面,我们硬要让ID重复那IE怎么搞呢?
这个时候我们还是可以继续使用document.getElementById获取对象,只不过我们只能获取ID重复的那些对象中在HTML Render时第一个出现的对象。而这时重复的ID会在引用时自动变成一个数组,ID重复的元素按Render的顺序依次存在于数组中。
程序题:我想启动一个线程执行特定的任务,任务的具体执行内容定义在TheRunnable类中(实现了java.lang.Runnable接口):
TheRunnable theRunnable = new TheRunnable();
以下哪个语句可用于启动theRunnable任务线程:_____
a) theRunnable.run();
b) theRunnable.start();
c) Thread thread = new Thread(theRunnable); thread.run();
d) Thread thread = new Thread(theRunnable); thread.start();
前言
全国青少年信息学(计算机)奥林匹克竞赛常常要用到许多经典算法,比如约瑟夫问题、螺旋方阵、汉诺塔、八皇后问题等,而 螺旋方阵问题是其中较为常用的一种。这类问题的算法分析对于计算机图形学、解析几何中的相关问题都有一定的启发性。尽管现有算法已取得了令人振奋的成绩, 但依然具有一定的片面性,或者说过于复杂。实际上,这个问题有不同的解决算法,鉴于这个问题具有一定的典型性,本文针对信息学奥林匹克竞赛这一问题进行了 全面系统的分析、归纳,从不同的角度对这个问题的算法进行分析并通过程序实现。使读者对这个问题在算法选择上有更大的余地,从而避免算法的单一性,同时对 于类似相关问题的解决也有一定的启发和帮助。
2 问题的描述与分析
关于螺旋方阵的输出主要是指将一些数据或符号按照一定的顺序输出到计算机的屏幕上或者是输出到一个指定的文件中去,输出的几种常见情况如下图(为简单起见,以输出5阶的数字螺旋方阵为例):
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
1 16 15 14 13
2 17 24 25 12
3 18 25 23 11
4 19 20 21 10
5 6 7 8 9
21 22 23 24 25
20 7 8 9 10
19 6 1 2 11
18 5 4 3 12
17 16 15 14 13
21 20 19 18 17
22 7 6 5 16
23 8 1 4 15
24 9 2 3 14
25 10 11 12 13
图1由外及里顺时针;图2由外及里逆时针;图3由里及外顺时针;图4由里及外逆时针
在实际应用中,输出的内容可以不尽相同。在上面的图1至图4中,按螺旋顺序输出的数显然有一定的规律,而实际输出的顺序往往不是按照螺旋顺序,通常是将上图中的数据按行(或按列)输出,因此这类问题的关键在于如何将有规律的数据与实际输出时的先后顺序对应起来。下面采用不同的算法来实现。
3 采用不同算法解决螺旋方阵的输出
3.1非递归算法
3.1.1 “海龟”算法(顺时针,由外及里)
参照海龟行走的做法,用一对变量A,B模拟海龟头的方向,根据屏幕坐标的特点,A、B的取值和“海龟头”方向有这样的关系:(0,1)表示向右;(0, -1)表示向左;(-1,0)表示向上;(1,0)表示向下;用另一对变量X,Y模拟海龟位置,“海龟”每前进一步,它的新位置即为X=X+A,Y=Y+B;要海龟向右转,就改变A、B的值,根据数学知识可以得出具体的变换公式是:C=A;A=B;B=-C。下面用自然语言对算法进行描述:让海龟先走n步,然后右转,再走n-1步,再右转,再走n-1步,再右转,再走n-2步,再右转,再走n-2步……如此类推,直到海龟前进的步数为0时停止;而每当“海龟”前进1步,就在它位置上显示一个数字,那么前进n步即重复执行“X:=X+A,Y:=Y+B”语句n次。但如何让下两个循环的重复次数都为n-1呢?解决的方法是:循环n次后,让n的值减少0.5,然后再转回执行同样的循环。扩展到显示n位数,则须留n列的位置,也就是说,海龟水平方向每次得前进n步,才有足够的位置显示大一点的数字方阵,需把Y=Y+B改成Y=Y+n*B就行了。“海龟”算法的优点是简洁清晰。
3.1.2 “分割”算法(逆时针,由外及里)
设螺旋方阵对应的一般二维数组如下:
a00 a01 a02 a03 a04
a10 a11 a12 a13 a14
a20 a21 a22 a23 a24
a30 a31 a32 a33 a34
a40 a41 a42 a43 a44
图5
按逆时针方向从外向内,一层层给下标变量赋值,由于阶数n的任意性,需考虑以下几个问题:层数k与阶数n的关系式,n由用户输入,k根据n来计算;定义变量value,赋值时让其自增;分析每层矩形四条边元素的下标变化规律,将方阵元素按逆时针方向分成四个部分:方阵左半边(三列),方阵下半边(二行),方阵右半边(两列),方阵上半边(二行)。
具体算法思想:以5阶方阵为例,可判断 k=[(n+1)/2]=3,用循环控制产生的层数,语句为for(k=0,k <(n+1)/2;k++)。
Step1:找出方阵左半边列规律:列下标正好是层数k的值,行下标在第一列从0变到4,第二列从1变到3,在第三列从2变到2,故推导出n阶螺旋方阵左半边由外到内的列循环结构:for(i=k;i <n-k;i++) mat[i][k]=value++;此循环执行一次,产生一列元素,循环执行的次数由外循环来控制。
Step2:找出方阵下半边行规律:行下标从4变到3,每层取值为n―k―1;列下标由外到内第一行从1变到4(a40已产生),第二行(a30 、a31已产生)从2变到3,第三行只有一个元素a22,故推导出n阶螺旋方阵下半边行循环结构:for(i=k+1;i <n-k;i++) mat[n-k-1][i]=value++;
Step3:找出方阵右半边列规律:行下标第一列从3变化到0(a44已产生),第二列从2变到1(a43、a33、a03已产生),可推断行的初值为n-k-2;列下标没变化,两列的下标分别为4、3,故推断出右半边的列可由下列循环结构完成:for(i=n-k-2;i >=k;i--) mat[i][n-k-1]=value++;
Step4:找出方阵上半边行规律:已经产生了的元素不能再重新赋值,而行下标可用层次k来表示,列下标与右半边行下标变化规律一样,由此推断出上半边的行可由下列循环结构完成:for(i=n-k-2;i >k;i--) mat[k][i]=value++。
当k取一个值时,以上四个循环依序各产生一列或一行元素,由此产生一层元素,当k在变化范围[0…(n+1)/2]内依次取值时,四个循环轮流执行,一个数字螺旋方阵就这样生成了。
3.2 递归算法
分析图五容易看出,当由外及里顺时针旋转时,最外层数据输出后,内层的图形只不过是层数减少了,即问题的规模变小了,但问题的性质没有发生变化,新问题和原问题仍然可以采用相同的解法。所以这一问题完全可以采用递归的方法来求解。具体的算法描述如下。
Step1:初始化。把需要输出的数据放入一维数组,设为b[1..n*n]。因为是n阶方阵,所以全部元素共有n2个,输出b[1]到b[n*n]的顺序是方阵顺时针旋转的顺序。
Step2:把b数组中的每个元素放入到二维数组a[i][j](图5)中去,如b[1]放入a[0][0]中,b[2]放入a[0][1]中,……,b[6]放入a[1][4]中……,其它元素依次放入。
Step3:按行输出数组元素a[i][j]即可。
上述算法中,难点在于如何将b数组放入到a[i][j]数组对应的分量中去。为此,对step2进行求精并使用递归来解决。具体做法:将数组a初始化为0。设置变量direction作为方向标志。当direction为1、2、3、4时,分别表示向右、向下、向左、向上。并编写如下的递归子程序walk(x,y,direction,k)。其中参数x,y表示数组的下标。k是计数器。当 k>n*n 为递归出口。
case direction of
{right } 1: if到右边界then 向下拐 else 向右输出;
{down} 2: if到下边界 then 向左拐 else 向下输出;
{left} 3: if到左边界 then 向上拐 else 向左输出;
{up} 4: if 到上边界 then 向右拐 else 向上输出。
end;{end case}
3.3 算法实现
限于篇幅,本文仅给出递归算法的主要程序段(pascal语言)
procedure walk(x,y,direction,k:integer);
begin
if k>n*n then 按行输出a数组;
a[x,y]:=b[k];
case direction of
{right}1: if (y=n) or (a[x,y+1]<>0) then walk(x+1,y,2,k+1) else walk(x,y+1,1,k+1);
{down}2: if (x=n) or (a[x+1,y]<>0) then walk(x,y-1,3,k+1) else walk(x+1,y,2,k+1);
{left} 3: if (y=1) or (a[x,y-1]<>0) then walk(x-1,y,4,k+1) else walk(x,y-1,3,k+1);
{up} 4: if (x=1) or (a[x-1,y]<>0) then walk(x,y+1,1,k+1) else walk(x-1,y,4,k+1)
end;
begin{main}
fillchar(a,sizeof(a),0);
writeln('please input a integer for n:');
readln(n);
walk(1,1,1,1);
end.{end main}
4 结束语
关于螺旋方阵的输出算法主要有上述几种,其他几种方阵的输出,可以仿照上述的算法分析加以实现。相对而言,递 归算法较为简洁,但是时间复杂度要高一些,对于输出高阶螺旋方阵时,时间很长。另外在空间复杂度方面,采用数组这种数据结构,显然有一定的局限性,如果使 用链表来存储,将会尽可能地避免空间不足的现象。另外,上述问题也可以使用一个模板式的子程序来完成,这时要求输入的参数要包括:从外还是从里螺旋、顺时 针还是逆时针,起点坐标等参数,对于从里向外螺旋时,还要考虑螺旋方阵的阶数是奇数还是偶数,分别给予不同的处理。
本篇文章来源于 义乌信息技术教研网 原文链接:http://www.ywhs.net/itedu/html/aosaifudao/mingshifudao/20071125/47.html
Java最初是在浏览器和客户端机器中粉墨登场的。当时,很多人质疑它是否适合做服务器端的开发。现在,随着对Java2平台企业版(J2EE)第三方支持的增多,Java被广泛接纳为开发企业级服务器端解决方案的首选平台之一。
J2EE平台由一整套服务(Services)、应用程序接口(APIs)和协议构成,它对开发基于Web的多层应用提供了功能支持。
在本文中我将解释支撑J2EE的13种核心技术:JDBC, JNDI, EJBs, RMI, JSP, Java servlets, XML, JMS, Java IDL, JTS, JTA, JavaMail 和 JAF,同时还将描述在何时、何处需要使用这些技术。当然,我还要介绍这些不同的技术之间是如何交互的。
此外,为了让您更好地感受J2EE的真实应用,我将在WebLogic应用服务器,来自BEA Systems公司的一种广为应用的产品环境下来介绍这些技术。不论对于WebLogic应用服务器和J2EE的新手,还是那些想了解J2EE能带来什么好处的项目管理者和系统分析员,相信本文一定很有参考价值。
宏观印象: 分布式结构和J2EE
过去,二层化应用 -- 通常被称为client/server应用 -- 是大家谈论的最多的。在很多情况下,服务器提供的惟一服务就是数据库服务。在这种解决方案中,客户端程序负责数据访问、实现业务逻辑、用合适的样式显示结果、弹出预设的用户界面、接受用户输入等。client/server结构通常在第一次部署的时候比较容易,但难于升级或改进,而且经常基于某种专有的协议,通常是某种数据库协议。它使得重用业务逻辑和界面逻辑非常困难。更重要的是,在Web时代,二层化应用通常不能体现出很好的伸缩性,因而很难适应Internet的要求。
Sun设计J2EE的部分起因就是想解决二层化结构的缺陷。于是,J2EE定义了一套标准来简化N层企业级应用的开发。它定义了一套标准化的组件,并为这些组件提供了完整的服务。J2EE还自动为应用程序处理了很多实现细节,如安全、多线程等。
用J2EE开发N层应用包括将二层化结构中的不同层面切分成许多层。一个N层化应用A能够为以下的每种服务提供一个分开的层:
显示:在一个典型的Web应用中,客户端机器上运行的浏览器负责实现用户界面。
动态生成显示: 尽管浏览器可以完成某些动态内容显示,但为了兼容不同的浏览器,这些动态生成工作应该放在Web服务器端进行,使用JSP、Servlets,或者XML(可扩展标记语言)和(可扩展样式表语言)。
业务逻辑:业务逻辑适合用Session EJBs(后面将介绍)来实现。
数据访问:数据访问适合用Entity EJBs(后面将介绍)和JDBC来实现。
后台系统集成: 同后台系统的集成可能需要用到许多不同的技术,至于何种最佳需要根据后台系统的特征而定。
您可能开始诧异:为什么有这么多的层?事实上,多层方式可以使企业级应用具有很强的伸缩性,它允许每层专注于特定的角色。例如,让Web服务器负责提供页面,应用服务器处理应用逻辑,而数据库服务器提供数据库服务。
由于J2EE建立在Java2平台标准版(J2SE)的基础上,所以具备了J2SE的所有优点和功能。包括“编写一次,到处可用”的可移植性、通过JDBC访问数据库、同原有企业资源进行交互的CORBA技术,以及一个经过验证的安全模型。在这些基础上,J2EE又增加了对EJB(企业级Java组件)、Java servlets、Java服务器页面(JSPs)和XML技术的支持。
分布式结构与WebLogic应用服务器
J2EE提供了一个框架--一套标准API--用于开发分布式结构的应用,这个框架的实际实现留给了第三方厂商。部分厂商只是专注于整个J2EE架构中的的特定组件,例如Apache的Tomcat提供了对JSP和servlets的支持,BEA系统公司则通过其WebLogic应用服务器产品为整个J2EE规范提供了一个较为完整的实现。
WebLogic服务器已使建立和部署伸缩性较好的分布式应用的过程大为简化。WebLogic和J2EE代你处理了大量常规的编程任务,包括提供事务服务、安全领域、可靠的消息、名字和目录服务、数据库访问和连接池、线程池、负载平衡和容错处理等。
通过以一种标准、易用的方式提供这些公共服务,象WebLogic服务器这样的产品造就了具有更好伸缩性和可维护性的应用系统,使其为大量的用户提供了增长的可用性。
J2EE技术
在接下来的部分里,我们将描述构成J2EE的各种技术,并且了解WebLogic服务器是如何在一个分布式应用中对它们进行支持的。最常用的J2EE技术应该是JDBC、JNDI、EJB、JSP和servlets,对这些我们将作更仔细的考察。
Java Database Connectivity (JDBC)
JDBC API以一种统一的方式来对各种各样的数据库进行存取。和ODBC一样,JDBC为开发人员隐藏了不同数据库的不同特性。另外,由于JDBC建立在Java的基础上,因此还提供了数据库存取的平台独立性。
JDBC定义了4种不同的驱动程序,现分述如下:
类型 1: JDBC-ODBC Bridge
在JDBC出现的初期,JDBC-ODBC桥显然是非常有实用意义的,通过JDBC-ODBC桥,开发人员可以使用JDBC来存取ODBC数据源。不足的是,他需要在客户端安装ODBC驱动程序,换句话说,必须安装Microsoft Windows的某个版本。使用这一类型你需要牺牲JDBC的平台独立性。另外,ODBC驱动程序还需要具有客户端的控制权限。
类型 2: JDBC-native driver bridge
JDBC本地驱动程序桥提供了一种JDBC接口,它建立在本地数据库驱动程序的顶层,而不需要使用ODBC。 JDBC驱动程序将对数据库的API从标准的JDBC调用转换为本地调用。使用此类型需要牺牲JDBC的平台独立性,还要求在客户端安装一些本地代码。
类型 3: JDBC-network bridge
JDBC网络桥驱动程序不再需要客户端数据库驱动程序。它使用网络上的中间服务器来存取数据库。这种应用使得以下技术的实现有了可能,这些技术包括负载均衡、连接缓冲池和数据缓存等。由于第3种类型往往只需要相对更少的下载时间,具有平台独立性,而且不需要在客户端安装并取得控制权,所以很适合于Internet上的应用。
类型 4: Pure Java driver
第4种类型通过使用一个纯Java数据库驱动程序来执行数据库的直接访问。此类型实际上在客户端实现了2层结构。要在N-层结构中应用,一个更好的做法是编写一个EJB,让它包含存取代码并提供一个对客户端具有数据库独立性的服务。
WebLogic服务器为一些通常的数据库提供了JDBC驱动程序,包括Oracle, Sybase, Microsoft SQL Server以及Informix。它也带有一种JDBC驱动程序用于Cloudscape,这是一种纯Java的DBMS,WebLogic服务器中带有该数据库的评估版本。
以下让我们看一个实例。
JDBC实例
在这个例子中我们假定你已经在Cloudscape中建立了一个PhoneBook数据库,并且包含一个表,名为 CONTACT_TABLE ,它带有2个字段:NAME 和 PHONE。 开始的时候先装载Cloudscape JDBC driver,并请求 driver manager得到一个对PhoneBook Cloudscape数据库的连接。通过这一连接,我们可以构造一个 Statement 对象并用它来执行一个简单的SQL查询。最后,用循环来遍历结果集的所有数据,并用标准输出将NAME和PHONE字段的内容进行输出。
创建新表:
create table tabname(col1 type1 [not null] [primary key],col2 type2 [not null],..)
根据已有的表创建新表:
A:create table tab_new like tab_old
B:create table tab_new as select col1,col2… from tab_old definition only
actionMessage怎么能保存到session中哪!!太占用服务器资源了。防止刷新比较好的办法是利用token来解决就可以了阿:
就你的情况来看我给你举个例子
在Action中的add方法中,我们需要将Token值明确的要求保存在页面中,只需增加一条语句:saveToken(request);,如下所示:
public ActionForward add(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
//前面的处理省略
saveToken(request);
//转发到需要录入信息的页面
return mapping.findForward("add");
}
在Action的insert方法中,我们根据表单中的Token值与服务器端的Token值比较,如下所示:
//处理信息录入的action
public ActionForward insert(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
if (isTokenValid(request, true)) {
// 表单不是重复提交正常执行
} else {
//表单重复提交
saveToken(request);
//给客户端提示错误,当然这里也就是你把ActionMessages保存到request范围内,然后forward到错误页面
}
}
执行的流程:add(Action)->信息录入页面(jsp)->insert(Action)
综上,其实你选择重定向到页面无非就是为了让request失效保证不能重复提交,而恰恰你的错误信息又是保存到了request范围内了,所以呵呵出现问题了,利用token来解决这个问题吧
了,至于token我再lz解释一下:
Struts的Token机制能够很好的解决表单重复提交的问题,基本原理是:服务器端在处理到达的请求之前,会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较,看是否匹配。在处理完该请求后,且在答复发送给客户端之前,将会产生一个新的令牌,该令牌除传给客户端以外,也会将用户会话中保存的旧的令牌进行替换。这样如果用户回退到刚才的提交页面并再次提交的话,客户端传过来的令牌就和服务器端的令牌不一致,从而有效地防止了重复提交的发生。
这时其实也就是两点,第一:你需要在请求中有这个令牌值,请求中的令牌值如何保存,其实就和我们平时在页面中保存一些信息是一样的,通过隐藏字段来保存,保存的形式如: 〈input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae"〉,这个value是TokenProcessor类中的generateToken()获得的,是根据当前用户的session id和当前时间的long值来计算的。第二:在客户端提交后,我们要根据判断在请求中包含的值是否和服务器的令牌一致,因为服务器每次提交都会生成新的Token,所以,如果是重复提交,客户端的Token值和服务器端的Token值就会不一致。
http://www.oracle.com/technology/sample_code/tech/java/codesnippet/webservices/attachment/index.html
http://www.ibm.com/developerworks/xml/library/x-tippass.html