2008年5月29日
#
刪除 ActiveX 控件,請(qǐng)按照相應(yīng)部分中的步驟操作。
Internet Explorer 3.0、3.01 和 3.02
- 單擊“開(kāi)始”,指向“設(shè)置”,單擊“控制面板”,雙擊“添加/刪除程序”,然后單擊“安裝/卸載”選項(xiàng)卡。
- 如果您要?jiǎng)h除的 ActiveX 控件出現(xiàn)在安裝的程序列表中,請(qǐng)單擊該 ActiveX 控件,單擊“添加/刪除”,然后按照屏幕上的說(shuō)明操作。如果該 ActiveX 控件沒(méi)有出現(xiàn)在安裝的程序列表中,則繼續(xù)執(zhí)行下一步。
- 單擊“開(kāi)始”,單擊“運(yùn)行”,在“打開(kāi)”框中鍵入下列行,然后單擊“確定”:
regsvr32 drive:\windows\occache\filename.ocx /u
注意:drive 是 Windows 文件夾所在的驅(qū)動(dòng)器號(hào),windows 是安裝 Windows 的文件夾名,而 filename.ocx 是您想要?jiǎng)h除的 ActiveX 控件。
注意:如果您不知道要?jiǎng)h除的 ActiveX 控件 (.ocx) 的文件名,則可以通過(guò)查看安裝或使用 ActiveX 控件的網(wǎng)頁(yè)的超文本標(biāo)記語(yǔ)言 (HTML) 源文件來(lái)確定該文件名。要查看一個(gè)網(wǎng)頁(yè)的 HTML 源文件,請(qǐng)右鍵單擊該網(wǎng)頁(yè)的空白區(qū)域,然后單擊“查看源文件”。
- 在 Windows 資源管理器或 Windows NT 資源管理器中,單擊 Windows\Occache 文件夾中的 .ocx 文件,然后單擊“文件”菜單上的“刪除”。
Occache 是在 Internet Explorer 3.x 的所有版本中安裝有 ActiveX 控件的文件夾的名稱(chēng)。Regsvr32.exe 文件是由 Internet Explorer 安裝的,并且可用于注冊(cè)和刪除 ActiveX 控件的注冊(cè)表項(xiàng)。
Internet Explorer 4.x 或更高版本(所有平臺(tái))
Internet Explorer 4.x 或更高版本,包括 Occache.dll 文件,該文件可用于使用“shell 文件夾”枚舉、更新和安全地卸載 ActiveX 控件。
- 單擊“開(kāi)始”,指向“設(shè)置”,單擊“控制面板”,雙擊“添加/刪除程序”,然后單擊“安裝/卸載”選項(xiàng)卡。
- 如果您要?jiǎng)h除的 ActiveX 控件出現(xiàn)在安裝的程序列表中,請(qǐng)單擊該 ActiveX 控件,單擊“添加/刪除”,然后按照屏幕上的說(shuō)明操作。如果該 ActiveX 控件沒(méi)有出現(xiàn)在安裝的程序列表中,則繼續(xù)執(zhí)行下一步。
- 在 Windows 資源管理器或 Windows NT 資源管理器中,雙擊 Windows\Downloaded Program Files 文件夾或 Winnt\Downloaded Program Files 文件夾,右鍵單擊您想要?jiǎng)h除的 ActiveX 控件,然后單擊“刪除”。
- 在系統(tǒng)提示您是否刪除該 ActiveX 控件后,單擊“是”。
重要說(shuō)明:如果您運(yùn)行的是 Internet Explorer 4.0,則不應(yīng)刪除以下 ActiveX 控件:
- DirectAnimation Java Classes
- Internet Explorer Classes for Java
- Microsoft XML Parser for Java
- Win32 Classes
Internet Explorer 5.0 或更高版本不要求 Downloaded Program Files 文件中的這些組件。
刪除 ActiveX 控件時(shí)出現(xiàn)的錯(cuò)誤消息
在您嘗試使用 Occache shell 文件夾刪除一個(gè) ActiveX 控件時(shí),可能顯示以下錯(cuò)誤消息之一:
- 共享沖突 這些程序文件當(dāng)前正由一個(gè)或多個(gè)程序使用。請(qǐng)關(guān)閉一些程序,然后重試。您可能需要重新啟動(dòng) Windows。
- 組件刪除 即將刪除 Windows 系統(tǒng) DLL:(<path\filename>)。是否刪除?
共享沖突:
如果您要嘗試刪除的 ActiveX 控件當(dāng)前在內(nèi)存中由 Internet Explorer 或“活動(dòng)桌面”組件加載,則顯示此錯(cuò)誤消息。
要解決此錯(cuò)誤消息,請(qǐng)按照下列步驟操作:
- 關(guān)閉所有打開(kāi)的 Internet Explorer 窗口。
- 禁用“活動(dòng)桌面”。為此,請(qǐng)右鍵單擊桌面上的空白區(qū)域,指向“活動(dòng)桌面”,然后單擊“查看網(wǎng)頁(yè)”以清除該復(fù)選標(biāo)記。
- 按照本文中前面部分的“Internet Explorer 4.0 或更高版本”部分中介紹的步驟,刪除該 ActiveX 控件。
注意:您最好在刪除 ActiveX 控件前重新啟動(dòng) Windows。
組件刪除:
僅當(dāng)您要?jiǎng)h除的 ActiveX 控件向已注冊(cè)的 Occache 文件夾以外的文件夾(例如,Windows\System 或 Winnt\System32)安裝文件時(shí),該消息才出現(xiàn)在 4.01 Service Pack 1 (SP1) 之前的 Internet Explorer 4 版本中。Occache 不是總能確定這些文件是否正由其程序共享。
如果您確定消息中顯示的一個(gè)或多個(gè)文件未由 Windows 或其他程序使用,請(qǐng)單擊“是”。否則,單擊“否”。
注意:在 Internet Explorer 4.01 SP1 和更高版本中,Occache 不刪除(或提示您刪除)注冊(cè)的 Occache 文件夾之外的相關(guān)文件。
支持多個(gè) Occache 文件夾
Internet Explorer 4.0 和更高版本支持多個(gè) Occache 文件夾。Occache 文件夾的列表位于以下注冊(cè)表項(xiàng)中:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ActiveX Cache
默認(rèn)情況下,Internet Explorer 4.0 和更高版本使用 Windows\Downloaded Program Files 或 Winnt\Downloaded Program Files 文件夾。如果是從 Internet Explorer 3.x 升級(jí)的,則 Occache 和 Downloaded Program Files 文件夾可能都存在。在此情況下,所有新的 ActiveX 控件都安裝在 Downloaded Program Files 文件夾中,但以前安裝的 ActiveX 控件仍在 Occache 文件夾中工作。當(dāng)您在 Windows 資源管理器、Windows NT 資源管理器或“我的電腦”中打開(kāi) Occache 或 Downloaded Program Files 文件夾時(shí),將顯示所有 ActiveX 控件,而與該 ActiveX 控件的文件所在的文件夾無(wú)關(guān)。在此情況下,注冊(cè)表項(xiàng)中將出現(xiàn)以下字符串值:
"0"="C:\\WINDOWS\\OCCACHE"
"1"="C:\\WINDOWS\\Downloaded Program Files"
有關(guān) ActiveX 控件的其他信息,請(qǐng)參見(jiàn) Microsoft 知識(shí)庫(kù)中的以下文章:
154544 (http://support.microsoft.com/kb/154544/LN/ ) ActiveX 技術(shù)說(shuō)明
有關(guān) Internet Explorer 在發(fā)生沖突(例如,如果文件已存在)時(shí)如何下載 ActiveX 控件的信息,請(qǐng)參見(jiàn) Microsoft 知識(shí)庫(kù)中的以下文章:
196150 (http://support.microsoft.com/kb/196150/LN/ ) INFO:為什么會(huì)在代碼下載期間創(chuàng)建 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
在運(yùn)行里執(zhí)行: smc -stop
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");
問(wèn)題描述:使用ie6導(dǎo)出excel表正常,但是在IE7 下總是報(bào)錯(cuò):“ 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對(duì)環(huán)境的設(shè)置特別嚴(yán)格,常用到的有兩部分,一個(gè)是安全里面的“internet”設(shè)置,一個(gè)是“信任站點(diǎn)”的設(shè)置。
1>需要把站點(diǎn)加入信任站點(diǎn)列表;
2>設(shè)置“信任站點(diǎn)”項(xiàng)的“自定義級(jí)別”,啟用“對(duì)未標(biāo)記為可安全執(zhí)行 ActiveX控件初始化并執(zhí)行腳本”即可。
|
#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插件開(kāi)發(fā)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等幾個(gè)類(lèi)型的項(xiàng)目支持這個(gè))
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.
正則表達(dá)式(regular expression)
關(guān)鍵字:
正則表達(dá)式,Regular Expression
作者:笑容
發(fā)表于:2004年05月03日
最后更新:2005年01月17日
19:54
版權(quán)聲明:使用創(chuàng)作公用版權(quán)協(xié)議
引用地址:<a
>正則表達(dá)式(regular
expression)</a>
NAV: 笑容的八小時(shí)外 / 笑容的八小時(shí)外資料索引
如何創(chuàng)建一個(gè)網(wǎng)站 (HOW TO:
Initiate a website) Red Hat Enterprise
Linux 介紹
前言
正則表達(dá)式是煩瑣的,但是強(qiáng)大的,學(xué)會(huì)之后的應(yīng)用會(huì)讓你除了提高效率外,會(huì)給你帶來(lái)絕對(duì)的成就感。只要認(rèn)真去閱讀這些資料,加上應(yīng)用的時(shí)候進(jìn)行一定的參考,掌握正則表達(dá)式不是問(wèn)題。
索引
1._引子
2._正則表達(dá)式的歷史
3._正則表達(dá)式定義
3.1_普通字符
3.2_非打印字符
3.3_特殊字符
3.4_限定符
3.5_定位符
3.6_選擇
3.7_后向引用
4._各種操作符的運(yùn)算優(yōu)先級(jí)
5._全部符號(hào)解釋
6._部分例子
7._正則表達(dá)式匹配規(guī)則
7.1_基本模式匹配
7.2_字符簇
7.3_確定重復(fù)出現(xiàn)
目前,正則表達(dá)式已經(jīng)在很多軟件中得到廣泛的應(yīng)用,包括*nix(Linux,
Unix等),HP等操作系統(tǒng),PHP,C#,Java等開(kāi)發(fā)環(huán)境,以及很多的應(yīng)用軟件中,都可以看到正則表達(dá)式的影子。
正則表達(dá)式的使用,可以通過(guò)簡(jiǎn)單的辦法來(lái)實(shí)現(xiàn)強(qiáng)大的功能。為了簡(jiǎn)單有效而又不失強(qiáng)大,造成了正則表達(dá)式代碼的難度較大,學(xué)習(xí)起來(lái)也不是很容易,所以需要付出一些努力才行,入門(mén)之后參照一定的參考,使用起來(lái)還是比較簡(jiǎn)單有效的。
例子: ^.+@.+""..+$
這樣的代碼曾經(jīng)多次把我自己給嚇退過(guò)。可能很多人也是被這樣的代碼給嚇跑的吧。繼續(xù)閱讀本文將讓你也可以自由應(yīng)用這樣的代碼。
注意:這里的第7部分跟前面的內(nèi)容看起來(lái)似乎有些重復(fù),目的是把前面表格里的部分重新描述了一次,目的是讓這些內(nèi)容更容易理解。
正則表達(dá)式的“祖先”可以一直上溯至對(duì)人類(lèi)神經(jīng)系統(tǒng)如何工作的早期研究。Warren
McCulloch 和 Walter Pitts 這兩位神經(jīng)生理學(xué)家研究出一種數(shù)學(xué)方式來(lái)描述這些神經(jīng)網(wǎng)絡(luò)。
1956 年, 一位叫 Stephen Kleene 的數(shù)學(xué)家在 McCulloch 和 Pitts
早期工作的基礎(chǔ)上,發(fā)表了一篇標(biāo)題為“神經(jīng)網(wǎng)事件的表示法”的論文,引入了正則表達(dá)式的概念。正則表達(dá)式就是用來(lái)描述他稱(chēng)為“正則集的代數(shù)”的表達(dá)式,因此采用“正則表達(dá)式”這個(gè)術(shù)語(yǔ)。
隨后,發(fā)現(xiàn)可以將這一工作應(yīng)用于使用 Ken Thompson 的計(jì)算搜索算法的一些早期研究,Ken Thompson 是 Unix
的主要發(fā)明人。正則表達(dá)式的第一個(gè)實(shí)用應(yīng)用程序就是 Unix 中的 qed 編輯器。
如他們所說(shuō),剩下的就是眾所周知的歷史了。從那時(shí)起直至現(xiàn)在正則表達(dá)式都是基于文本的編輯器和搜索工具中的一個(gè)重要部分。
正則表達(dá)式(regular
expression)描述了一種字符串匹配的模式,可以用來(lái)檢查一個(gè)串是否含有某種子串、將匹配的子串做替換或者從某個(gè)串中取出符合某個(gè)條件的子串等。
- 列目錄時(shí), dir *.txt或ls
*.txt中的*.txt就不是一個(gè)正則表達(dá)式,因?yàn)檫@里*與正則式的*的含義是不同的。
正則表達(dá)式是由普通字符(例如字符 a 到
z)以及特殊字符(稱(chēng)為元字符)組成的文字模式。正則表達(dá)式作為一個(gè)模板,將某個(gè)字符模式與所搜索的字符串進(jìn)行匹配。
由所有那些未顯式指定為元字符的打印和非打印字符組成。這包括所有的大寫(xiě)和小寫(xiě)字母字符,所有數(shù)字,所有標(biāo)點(diǎn)符號(hào)以及一些符號(hào)。
字符 |
含義 |
"cx |
匹配由x指明的控制字符。例如, "cM 匹配一個(gè) Control-M 或回車(chē)符。x 的值必須為 A-Z
或 a-z 之一。否則,將 c 視為一個(gè)原義的 'c' 字符。 |
"f |
匹配一個(gè)換頁(yè)符。等價(jià)于 "x0c 和 "cL。 |
"n |
匹配一個(gè)換行符。等價(jià)于 "x0a 和 "cJ。 |
"r |
匹配一個(gè)回車(chē)符。等價(jià)于 "x0d 和 "cM。 |
"s |
匹配任何空白字符,包括空格、制表符、換頁(yè)符等等。等價(jià)于 [ "f"n"r"t"v]。 |
"S |
匹配任何非空白字符。等價(jià)于 [^ "f"n"r"t"v]。 |
"t |
匹配一個(gè)制表符。等價(jià)于 "x09 和 "cI。 |
"v |
匹配一個(gè)垂直制表符。等價(jià)于 "x0b 和
"cK。 |
所謂特殊字符,就是一些有特殊含義的字符,如上面說(shuō)的"*.txt"中的*,簡(jiǎn)單的說(shuō)就是表示任何字符串的意思。如果要查找文件名中有*的文件,則需要對(duì)*進(jìn)行轉(zhuǎn)義,即在其前加一個(gè)"。ls
"*.txt。正則表達(dá)式有以下特殊字符。
特別字符 |
說(shuō)明 |
$ |
匹配輸入字符串的結(jié)尾位置。如果設(shè)置了 RegExp 對(duì)象的 Multiline 屬性,則 $ 也匹配
'"n' 或 '"r'。要匹配 $ 字符本身,請(qǐng)使用 "$。 |
( ) |
標(biāo)記一個(gè)子表達(dá)式的開(kāi)始和結(jié)束位置。子表達(dá)式可以獲取供以后使用。要匹配這些字符,請(qǐng)使用 "( 和
")。 |
* |
匹配前面的子表達(dá)式零次或多次。要匹配 * 字符,請(qǐng)使用 "*。 |
+ |
匹配前面的子表達(dá)式一次或多次。要匹配 + 字符,請(qǐng)使用 "+。 |
. |
匹配除換行符 "n之外的任何單字符。要匹配 .,請(qǐng)使用 "。 |
[ |
標(biāo)記一個(gè)中括號(hào)表達(dá)式的開(kāi)始。要匹配 [,請(qǐng)使用 "[。 |
? |
匹配前面的子表達(dá)式零次或一次,或指明一個(gè)非貪婪限定符。要匹配 ? 字符,請(qǐng)使用
"?。 |
" |
將下一個(gè)字符標(biāo)記為或特殊字符、或原義字符、或向后引用、或八進(jìn)制轉(zhuǎn)義符。例如, 'n' 匹配字符
'n'。'"n' 匹配換行符。序列 '""' 匹配 """,而 '"(' 則匹配 "("。 |
^ |
匹配輸入字符串的開(kāi)始位置,除非在方括號(hào)表達(dá)式中使用,此時(shí)它表示不接受該字符集合。要匹配 ^
字符本身,請(qǐng)使用 "^。 |
{ |
標(biāo)記限定符表達(dá)式的開(kāi)始。要匹配 {,請(qǐng)使用 "{。 |
| |
指明兩項(xiàng)之間的一個(gè)選擇。要匹配 |,請(qǐng)使用 "|。 |
- 構(gòu)造正則表達(dá)式的方法和創(chuàng)建數(shù)學(xué)表達(dá)式的方法一樣。也就是用多種元字符與操作符將小的表達(dá)式結(jié)合在一起來(lái)創(chuàng)建更大的表達(dá)式。正則表達(dá)式的組件可以是單個(gè)的字符、字符集合、字符范圍、字符間的選擇或者所有這些組件的任意組合。
限定符用來(lái)指定正則表達(dá)式的一個(gè)給定組件必須要出現(xiàn)多少次才能滿(mǎn)足匹配。有*或+或?或{n}或{n,}或{n,m}共6種。
*、+和?限定符都是貪婪的,因?yàn)樗鼈儠?huì)盡可能多的匹配文字,只有在它們的后面加上一個(gè)?就可以實(shí)現(xiàn)非貪婪或最小匹配。
正則表達(dá)式的限定符有:
字符 |
描述 |
* |
匹配前面的子表達(dá)式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。*
等價(jià)于{0,}。 |
+ |
匹配前面的子表達(dá)式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配
"z"。+ 等價(jià)于 {1,}。 |
? |
匹配前面的子表達(dá)式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does"
中的"do" 。? 等價(jià)于 {0,1}。 |
{n} |
n 是一個(gè)非負(fù)整數(shù)。匹配確定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的
'o',但是能匹配 "food" 中的兩個(gè) o。 |
{n,} |
n 是一個(gè)非負(fù)整數(shù)。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配
"foooood" 中的所有 o。'o{1,}' 等價(jià)于 'o+'。'o{0,}' 則等價(jià)于 'o*'。 |
{n,m} |
m 和 n 均為非負(fù)整數(shù),其中n <= m。最少匹配 n 次且最多匹配 m
次。例如,"o{1,3}" 將匹配 "fooooood" 中的前三個(gè) o。'o{0,1}' 等價(jià)于
'o?'。請(qǐng)注意在逗號(hào)和兩個(gè)數(shù)之間不能有空格。 |
用來(lái)描述字符串或單詞的邊界,^和$分別指字符串的開(kāi)始與結(jié)束,"b描述單詞的前或后邊界,"B表示非單詞邊界。
不能對(duì)定位符使用限定符。
用圓括號(hào)將所有選擇項(xiàng)括起來(lái),相鄰的選擇項(xiàng)之間用|分隔。但用圓括號(hào)會(huì)有一個(gè)副作用,是相關(guān)的匹配會(huì)被緩存,此時(shí)可用?:放在第一個(gè)選項(xiàng)前來(lái)消除這種副作用。
其中?:是非捕獲元之一,還有兩個(gè)非捕獲元是?=和?!,這兩個(gè)還有更多的含義,前者為正向預(yù)查,在任何開(kāi)始匹配圓括號(hào)內(nèi)的正則表達(dá)式模式的位置來(lái)匹配搜索字符串,后者為負(fù)向預(yù)查,在任何開(kāi)始不匹配該正則表達(dá)式模式的位置來(lái)匹配搜索字符串。
對(duì)一個(gè)正則表達(dá)式模式或部分模式兩邊添加圓括號(hào)將導(dǎo)致相關(guān)匹配存儲(chǔ)到一個(gè)臨時(shí)緩沖區(qū)中,所捕獲的每個(gè)子匹配都按照在正則表達(dá)式模式中從左至右所遇到的內(nèi)容存儲(chǔ)。存儲(chǔ)子匹配的緩沖區(qū)編號(hào)從
1 開(kāi)始,連續(xù)編號(hào)直至最大 99 個(gè)子表達(dá)式。每個(gè)緩沖區(qū)都可以使用 '"n' 訪問(wèn),其中 n
為一個(gè)標(biāo)識(shí)特定緩沖區(qū)的一位或兩位十進(jìn)制數(shù)。
可以使用非捕獲元字符 '?:', '?=', or '?!' 來(lái)忽略對(duì)相關(guān)匹配的保存。
相同優(yōu)先級(jí)的從左到右進(jìn)行運(yùn)算,不同優(yōu)先級(jí)的運(yùn)算先高后低。各種操作符的優(yōu)先級(jí)從高到低如下:
操作符 |
描述 |
" |
轉(zhuǎn)義符 |
(), (?:), (?=), [] |
圓括號(hào)和方括號(hào) |
*, +, ?, {n}, {n,}, {n,m} |
限定符 |
^, $, "anymetacharacter |
位置和順序 |
| |
“或”操作 |
字符 |
描述 |
" |
將下一個(gè)字符標(biāo)記為一個(gè)特殊字符、或一個(gè)原義字符、或一個(gè) 向后引用、或一個(gè)八進(jìn)制轉(zhuǎn)義符。例如,'n'
匹配字符 "n"。'"n' 匹配一個(gè)換行符。序列 '""' 匹配 """ 而 ""(" 則匹配 "("。 |
^ |
匹配輸入字符串的開(kāi)始位置。如果設(shè)置了 RegExp 對(duì)象的 Multiline 屬性,^ 也匹配
'"n' 或 '"r' 之后的位置。 |
$ |
匹配輸入字符串的結(jié)束位置。如果設(shè)置了RegExp 對(duì)象的 Multiline 屬性,$ 也匹配 '"n'
或 '"r' 之前的位置。 |
* |
匹配前面的子表達(dá)式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。*
等價(jià)于{0,}。 |
+ |
匹配前面的子表達(dá)式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配
"z"。+ 等價(jià)于 {1,}。 |
? |
匹配前面的子表達(dá)式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does"
中的"do" 。? 等價(jià)于 {0,1}。 |
{n} |
n 是一個(gè)非負(fù)整數(shù)。匹配確定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的
'o',但是能匹配 "food" 中的兩個(gè) o。 |
{n,} |
n 是一個(gè)非負(fù)整數(shù)。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配
"foooood" 中的所有 o。'o{1,}' 等價(jià)于 'o+'。'o{0,}' 則等價(jià)于 'o*'。 |
{n,m} |
m 和 n 均為非負(fù)整數(shù),其中n <= m。最少匹配 n 次且最多匹配 m
次。例如,"o{1,3}" 將匹配 "fooooood" 中的前三個(gè) o。'o{0,1}' 等價(jià)于
'o?'。請(qǐng)注意在逗號(hào)和兩個(gè)數(shù)之間不能有空格。 |
? |
當(dāng)該字符緊跟在任何一個(gè)其他限制符 (*, +, ?, {n}, {n,}, {n,m})
后面時(shí),匹配模式是非貪婪的。非貪婪模式盡可能少的匹配所搜索的字符串,而默認(rèn)的貪婪模式則盡可能多的匹配所搜索的字符串。例如,對(duì)于字符串 "oooo",'o+?'
將匹配單個(gè) "o",而 'o+' 將匹配所有 'o'。 |
. |
匹配除 ""n" 之外的任何單個(gè)字符。要匹配包括 '"n' 在內(nèi)的任何字符,請(qǐng)使用象 '[."n]'
的模式。 |
(pattern) |
匹配 pattern 并獲取這一匹配。所獲取的匹配可以從產(chǎn)生的 Matches
集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中則使用 $0…$9 屬性。要匹配圓括號(hào)字符,請(qǐng)使用 '"(' 或
'")'。 |
(?:pattern) |
匹配 pattern 但不獲取匹配結(jié)果,也就是說(shuō)這是一個(gè)非獲取匹配,不進(jìn)行存儲(chǔ)供以后使用。這在使用
"或" 字符 (|) 來(lái)組合一個(gè)模式的各個(gè)部分是很有用。例如, 'industr(?:y|ies) 就是一個(gè)比 'industry|industries'
更簡(jiǎn)略的表達(dá)式。 |
(?=pattern) |
正向預(yù)查,在任何匹配 pattern
的字符串開(kāi)始處匹配查找字符串。這是一個(gè)非獲取匹配,也就是說(shuō),該匹配不需要獲取供以后使用。例如,'Windows (?=95|98|NT|2000)' 能匹配
"Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的
"Windows"。預(yù)查不消耗字符,也就是說(shuō),在一個(gè)匹配發(fā)生后,在最后一次匹配之后立即開(kāi)始下一次匹配的搜索,而不是從包含預(yù)查的字符之后開(kāi)始。 |
(?!pattern) |
負(fù)向預(yù)查,在任何不匹配 pattern
的字符串開(kāi)始處匹配查找字符串。這是一個(gè)非獲取匹配,也就是說(shuō),該匹配不需要獲取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配
"Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的
"Windows"。預(yù)查不消耗字符,也就是說(shuō),在一個(gè)匹配發(fā)生后,在最后一次匹配之后立即開(kāi)始下一次匹配的搜索,而不是從包含預(yù)查的字符之后開(kāi)始 |
x|y |
匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 則匹配
"zood" 或 "food"。 |
[xyz] |
字符集合。匹配所包含的任意一個(gè)字符。例如, '[abc]' 可以匹配 "plain" 中的
'a'。 |
[^xyz] |
負(fù)值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain"
中的'p'。 |
[a-z] |
字符范圍。匹配指定范圍內(nèi)的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z'
范圍內(nèi)的任意小寫(xiě)字母字符。 |
[^a-z] |
負(fù)值字符范圍。匹配任何不在指定范圍內(nèi)的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到
'z' 范圍內(nèi)的任意字符。 |
"b |
匹配一個(gè)單詞邊界,也就是指單詞和空格間的位置。例如, 'er"b' 可以匹配"never" 中的
'er',但不能匹配 "verb" 中的 'er'。 |
"B |
匹配非單詞邊界。'er"B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的
'er'。 |
"cx |
匹配由 x 指明的控制字符。例如, "cM 匹配一個(gè) Control-M 或回車(chē)符。x 的值必須為
A-Z 或 a-z 之一。否則,將 c 視為一個(gè)原義的 'c' 字符。 |
"d |
匹配一個(gè)數(shù)字字符。等價(jià)于 [0-9]。 |
"D |
匹配一個(gè)非數(shù)字字符。等價(jià)于 [^0-9]。 |
"f |
匹配一個(gè)換頁(yè)符。等價(jià)于 "x0c 和 "cL。 |
"n |
匹配一個(gè)換行符。等價(jià)于 "x0a 和 "cJ。 |
"r |
匹配一個(gè)回車(chē)符。等價(jià)于 "x0d 和 "cM。 |
"s |
匹配任何空白字符,包括空格、制表符、換頁(yè)符等等。等價(jià)于 [ "f"n"r"t"v]。 |
"S |
匹配任何非空白字符。等價(jià)于 [^ "f"n"r"t"v]。 |
"t |
匹配一個(gè)制表符。等價(jià)于 "x09 和 "cI。 |
"v |
匹配一個(gè)垂直制表符。等價(jià)于 "x0b 和 "cK。 |
"w |
匹配包括下劃線(xiàn)的任何單詞字符。等價(jià)于'[A-Za-z0-9_]'。 |
"W |
匹配任何非單詞字符。等價(jià)于 '[^A-Za-z0-9_]'。 |
"xn |
匹配 n,其中 n 為十六進(jìn)制轉(zhuǎn)義值。十六進(jìn)制轉(zhuǎn)義值必須為確定的兩個(gè)數(shù)字長(zhǎng)。例如,'"x41' 匹配
"A"。'"x041' 則等價(jià)于 '"x04' & "1"。正則表達(dá)式中可以使用 ASCII 編碼。. |
"num |
匹配 num,其中 num 是一個(gè)正整數(shù)。對(duì)所獲取的匹配的引用。例如,'(.)"1'
匹配兩個(gè)連續(xù)的相同字符。 |
"n |
標(biāo)識(shí)一個(gè)八進(jìn)制轉(zhuǎn)義值或一個(gè)向后引用。如果 "n 之前至少 n 個(gè)獲取的子表達(dá)式,則 n
為向后引用。否則,如果 n 為八進(jìn)制數(shù)字 (0-7),則 n 為一個(gè)八進(jìn)制轉(zhuǎn)義值。 |
"nm |
標(biāo)識(shí)一個(gè)八進(jìn)制轉(zhuǎn)義值或一個(gè)向后引用。如果 "nm 之前至少有 nm 個(gè)獲得子表達(dá)式,則 nm
為向后引用。如果 "nm 之前至少有 n 個(gè)獲取,則 n 為一個(gè)后跟文字 m 的向后引用。如果前面的條件都不滿(mǎn)足,若 n 和 m 均為八進(jìn)制數(shù)字 (0-7),則
"nm 將匹配八進(jìn)制轉(zhuǎn)義值 nm。 |
"nml |
如果 n 為八進(jìn)制數(shù)字 (0-3),且 m 和 l 均為八進(jìn)制數(shù)字 (0-7),則匹配八進(jìn)制轉(zhuǎn)義值
nml。 |
"un |
匹配 n,其中 n 是一個(gè)用四個(gè)十六進(jìn)制數(shù)字表示的 Unicode 字符。例如, "u00A9
匹配版權(quán)符號(hào) (?)。 |
正則表達(dá)式 |
說(shuō)明 |
/"b([a-z]+) "1"b/gi |
一個(gè)單詞連續(xù)出現(xiàn)的位置 |
/("w+):"/"/([^/:]+)(:"d*)?([^# ]*)/ |
將一個(gè)URL解析為協(xié)議、域、端口及相對(duì)路徑 |
/^(?:Chapter|Section) [1-9][0-9]{0,1}$/ |
定位章節(jié)的位置 |
/[-a-z]/ |
A至z共26個(gè)字母再加一個(gè)-號(hào)。 |
/ter"b/ |
可匹配chapter,而不能terminal |
/"Bapt/ |
可匹配chapter,而不能aptitude |
/Windows(?=95 |98 |NT )/ |
可匹配Windows95或Windows98或WindowsNT,當(dāng)找到一個(gè)匹配后,從Windows后面開(kāi)始進(jìn)行下一次的檢索匹配。 |
7.1
基本模式匹配
一切從最基本的開(kāi)始。模式,是正規(guī)表達(dá)式最基本的元素,它們是一組描述字符串特征的字符。模式可以很簡(jiǎn)單,由普通的字符串組成,也可以非常復(fù)雜,往往用特殊的字符表示一個(gè)范圍內(nèi)的字符、重復(fù)出現(xiàn),或表示上下文。例如:
^once
這個(gè)模式包含一個(gè)特殊的字符^,表示該模式只匹配那些以once開(kāi)頭的字符串。例如該模式與字符串"once upon a time"匹配,與"There
once was a man from NewYork"不匹配。正如如^符號(hào)表示開(kāi)頭一樣,$符號(hào)用來(lái)匹配那些以給定模式結(jié)尾的字符串。
bucket$
這個(gè)模式與"Who kept all of this cash in a
bucket"匹配,與"buckets"不匹配。字符^和$同時(shí)使用時(shí),表示精確匹配(字符串與模式一樣)。例如:
^bucket$
只匹配字符串"bucket"。如果一個(gè)模式不包括^和$,那么它與任何包含該模式的字符串匹配。例如:模式
once
與字符串
There once was a man from NewYork
Who kept all of his cash in a
bucket.
是匹配的。
在該模式中的字母(o-n-c-e)是字面的字符,也就是說(shuō),他們表示該字母本身,數(shù)字也是一樣的。其他一些稍微復(fù)雜的字符,如標(biāo)點(diǎn)符號(hào)和白字符(空格、制表符等),要用到轉(zhuǎn)義序列。所有的轉(zhuǎn)義序列都用反斜杠(")打頭。制表符的轉(zhuǎn)義序列是:"t。所以如果我們要檢測(cè)一個(gè)字符串是否以制表符開(kāi)頭,可以用這個(gè)模式:
^"t
類(lèi)似的,用"n表示“新行”,"r表示回車(chē)。其他的特殊符號(hào),可以用在前面加上反斜杠,如反斜杠本身用""表示,句號(hào).用".表示,以此類(lèi)推。
7.2
字符簇
在INTERNET的程序中,正規(guī)表達(dá)式通常用來(lái)驗(yàn)證用戶(hù)的輸入。當(dāng)用戶(hù)提交一個(gè)FORM以后,要判斷輸入的電話(huà)號(hào)碼、地址、EMAIL地址、信用卡號(hào)碼等是否有效,用普通的基于字面的字符是不夠的。
所以要用一種更自由的描述我們要的模式的辦法,它就是字符簇。要建立一個(gè)表示所有元音字符的字符簇,就把所有的元音字符放在一個(gè)方括號(hào)里:
[AaEeIiOoUu]
這個(gè)模式與任何元音字符匹配,但只能表示一個(gè)字符。用連字號(hào)可以表示一個(gè)字符的范圍,如:
[a-z] //匹配所有的小寫(xiě)字母
[A-Z] //匹配所有的大寫(xiě)字母
[a-zA-Z] //匹配所有的字母
[0-9]
//匹配所有的數(shù)字
[0-9"."-] //匹配所有的數(shù)字,句號(hào)和減號(hào)
[ "f"r"t"n] //匹配所有的白字符
同樣的,這些也只表示一個(gè)字符,這是一個(gè)非常重要的。如果要匹配一個(gè)由一個(gè)小寫(xiě)字母和一位數(shù)字組成的字符串,比如"z2"、"t6"或"g7",但不是"ab2"、"r2d3"
或"b52"的話(huà),用這個(gè)模式:
^[a-z][0-9]$
盡管[a-z]代表26個(gè)字母的范圍,但在這里它只能與第一個(gè)字符是小寫(xiě)字母的字符串匹配。
前面曾經(jīng)提到^表示字符串的開(kāi)頭,但它還有另外一個(gè)含義。當(dāng)在一組方括號(hào)里使用^是,它表示“非”或“排除”的意思,常常用來(lái)剔除某個(gè)字符。還用前面的例子,我們要求第一個(gè)字符不能是數(shù)字:
^[^0-9][0-9]$
這個(gè)模式與"&5"、"g7"及"-2"是匹配的,但與"12"、"66"是不匹配的。下面是幾個(gè)排除特定字符的例子:
[^a-z] //除了小寫(xiě)字母以外的所有字符
[^"""/"^] //除了(")(/)(^)之外的所有字符
[^"""']
//除了雙引號(hào)(")和單引號(hào)(')之外的所有字符
特殊字符"."
(點(diǎn),句號(hào))在正規(guī)表達(dá)式中用來(lái)表示除了“新行”之外的所有字符。所以模式"^.5$"與任何兩個(gè)字符的、以數(shù)字5結(jié)尾和以其他非“新行”字符開(kāi)頭的字符串匹配。模式"."可以匹配任何字符串,除了空串和只包括一個(gè)“新行”的字符串。
PHP的正規(guī)表達(dá)式有一些內(nèi)置的通用字符簇,列表如下:
字符簇 含義
[[:alpha:]] 任何字母
[[:digit:]] 任何數(shù)字
[[:alnum:]] 任何字母和數(shù)字
[[:space:]] 任何白字符
[[:upper:]] 任何大寫(xiě)字母
[[:lower:]] 任何小寫(xiě)字母
[[:punct:]] 任何標(biāo)點(diǎn)符號(hào)
[[:xdigit:]] 任何16進(jìn)制的數(shù)字,相當(dāng)于[0-9a-fA-F]
7.3
確定重復(fù)出現(xiàn)
到現(xiàn)在為止,你已經(jīng)知道如何去匹配一個(gè)字母或數(shù)字,但更多的情況下,可能要匹配一個(gè)單詞或一組數(shù)字。一個(gè)單詞有若干個(gè)字母組成,一組數(shù)字有若干個(gè)單數(shù)組成。跟在字符或字符簇后面的花括號(hào)({})用來(lái)確定前面的內(nèi)容的重復(fù)出現(xiàn)的次數(shù)。
字符簇 含義
^[a-zA-Z_]$ 所有的字母和下劃線(xiàn)
^[[:alpha:]]{3}$ 所有的3個(gè)字母的單詞
^a$ 字母a
^a{4}$ aaaa
^a{2,4}$ aa,aaa或aaaa
^a{1,3}$ a,aa或aaa
^a{2,}$
包含多于兩個(gè)a的字符串
^a{2,} 如:aardvark和aaab,但apple不行
a{2,}
如:baad和aaa,但Nantucket不行
"t{2} 兩個(gè)制表符
.{2} 所有的兩個(gè)字符
這些例子描述了花括號(hào)的三種不同的用法。一個(gè)數(shù)字,{x}的意思是“前面的字符或字符簇只出現(xiàn)x次”;一個(gè)數(shù)字加逗號(hào),{x,}的意思是“前面的內(nèi)容出現(xiàn)x或更多的次數(shù)”;兩個(gè)用逗號(hào)分隔的數(shù)字,{x,y}表示“前面的內(nèi)容至少出現(xiàn)x次,但不超過(guò)y次”。我們可以把模式擴(kuò)展到更多的單詞或數(shù)字:
^[a-zA-Z0-9_]{1,}$ //所有包含一個(gè)以上的字母、數(shù)字或下劃線(xiàn)的字符串
^[0-9]{1,}$ //所有的正數(shù)
^"-{0,1}[0-9]{1,}$ //所有的整數(shù)
^"-{0,1}[0-9]{0,}".{0,1}[0-9]{0,}$ //所有的小數(shù)
最后一個(gè)例子不太好理解,是嗎?這么看吧:與所有以一個(gè)可選的負(fù)號(hào)("-{0,1})開(kāi)頭(^)、跟著0個(gè)或更多的數(shù)字([0-9]{0,})、和一個(gè)可選的小數(shù)點(diǎn)(".{0,1})再跟上0個(gè)或多個(gè)數(shù)字([0-9]{0,}),并且沒(méi)有其他任何東西($)。下面你將知道能夠使用的更為簡(jiǎn)單的方法。
特殊字符"?"與{0,1}是相等的,它們都代表著:“0個(gè)或1個(gè)前面的內(nèi)容”或“前面的內(nèi)容是可選的”。所以剛才的例子可以簡(jiǎn)化為:
^"-?[0-9]{0,}".?[0-9]{0,}$
特殊字符"*"與{0,}是相等的,它們都代表著“0個(gè)或多個(gè)前面的內(nèi)容”。最后,字符"+"與
{1,}是相等的,表示“1個(gè)或多個(gè)前面的內(nèi)容”,所以上面的4個(gè)例子可以寫(xiě)成:
^[a-zA-Z0-9_]+$ //所有包含一個(gè)以上的字母、數(shù)字或下劃線(xiàn)的字符串
^[0-9]+$ //所有的正數(shù)
^"-?[0-9]+$
//所有的整數(shù)
^"-?[0-9]*".?[0-9]*$ //所有的小數(shù)
當(dāng)然這并不能從技術(shù)上降低正規(guī)表達(dá)式的復(fù)雜性,但可以使它們更容易閱讀。
參考文獻(xiàn):
JScript 和 VBScript 正則表達(dá)式
微軟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
|
正則表達(dá)式(regular
expression)對(duì)象包含一個(gè)正則表達(dá)式模式(pattern)。它具有用正則表達(dá)式模式去匹配或代替一個(gè)串(string)中特定字符(或字符集合)的屬性(properties)和方法(methods)。
要為一個(gè)單獨(dú)的正則表達(dá)式添加屬性,可以使用正則表達(dá)式構(gòu)造函數(shù)(constructor
function),無(wú)論何時(shí)被調(diào)用的預(yù)設(shè)置的正則表達(dá)式擁有靜態(tài)的屬性(the predefined RegExp object has static
properties that are set whenever any regular expression is used,
我不知道我翻得對(duì)不對(duì),將原文列出,請(qǐng)自行翻譯)。
- 創(chuàng)建:
一個(gè)文本格式或正則表達(dá)式構(gòu)造函數(shù)
文本格式: /pattern/flags
正則表達(dá)式構(gòu)造函數(shù): new
RegExp("pattern"[,"flags"]);
- 參數(shù)說(shuō)明:
pattern -- 一個(gè)正則表達(dá)式文本
flags -- 如果存在,將是以下值:
g: 全局匹配
i:
忽略大小寫(xiě)
gi: 以上組合
[注意] 文本格式的參數(shù)不用引號(hào),而在用構(gòu)造函數(shù)時(shí)的參數(shù)需要引號(hào)。如:/ab+c/i new
RegExp("ab+c","i")是實(shí)現(xiàn)一樣的功能。在構(gòu)造函數(shù)中,一些特殊字符需要進(jìn)行轉(zhuǎn)意(在特殊字符前加""")。如:re = new
RegExp("""w+")
正則表達(dá)式中的特殊字符
字符 |
含意 |
" |
做為轉(zhuǎn)意,即通常在"""后面的字符不按原來(lái)意義解釋?zhuān)?b/匹配字符"b",當(dāng)b前面加了反斜桿后/"b/,轉(zhuǎn)意為匹配一個(gè)單詞的邊界。
-或-
對(duì)正則表達(dá)式功能字符的還原,如"*"匹配它前面元字符0次或多次,/a*/將匹配a,aa,aaa,加了"""后,/a"*/將只匹配"a*"。
|
^ |
匹配一個(gè)輸入或一行的開(kāi)頭,/^a/匹配"an A",而不匹配"An a" |
$ |
匹配一個(gè)輸入或一行的結(jié)尾,/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),匹配這個(gè)集合中的任一一個(gè)字符(或元字符) |
[^xyz] |
不匹配這個(gè)集合中的任何一個(gè)字符 |
["b] |
匹配一個(gè)退格符 |
"b |
匹配一個(gè)單詞的邊界 |
"B |
匹配一個(gè)單詞的非邊界 |
"cX |
這兒,X是一個(gè)控制符,/"cM/匹配Ctrl-M |
"d |
匹配一個(gè)字?jǐn)?shù)字符,/"d/ = /[0-9]/ |
"D |
匹配一個(gè)非字?jǐn)?shù)字符,/"D/ = /[^0-9]/ |
"n |
匹配一個(gè)換行符 |
"r |
匹配一個(gè)回車(chē)符 |
"s |
匹配一個(gè)空白字符,包括"n,"r,"f,"t,"v等 |
"S |
匹配一個(gè)非空白字符,等于/[^"n"f"r"t"v]/ |
"t |
匹配一個(gè)制表符 |
"v |
匹配一個(gè)重直制表符 |
"w |
匹配一個(gè)可以組成單詞的字符(alphanumeric,這是我的意譯,含數(shù)字),包括下劃線(xiàn),如["w]匹配"$5.98"中的5,等于[a-zA-Z0-9]
|
"W |
匹配一個(gè)不可以組成單詞的字符,如["W]匹配"$5.98"中的$,等于[^a-zA-Z0-9]。 |
|
說(shuō)了這么多了,我們來(lái)看一些正則表達(dá)式的實(shí)際應(yīng)用的例子:
E-mail地址驗(yàn)證:
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>");
}
正則表達(dá)式對(duì)象的屬性及方法
預(yù)定義的正則表達(dá)式擁有有以下靜態(tài)屬性:input, multiline,
lastMatch, lastParen, leftContext,
rightContext和$1到$9。其中input和multiline可以預(yù)設(shè)置。其他屬性的值在執(zhí)行過(guò)exec或test方法后被根據(jù)不同條件賦以不同的值。許多屬性同時(shí)擁有長(zhǎng)和短(perl風(fēng)格)的兩個(gè)名字,并且,這兩個(gè)名字指向同一個(gè)值。(JavaScript模擬perl的正則表達(dá)式)
正則表達(dá)式對(duì)象的屬性
屬性 |
含義 |
$1...$9 |
如果它(們)存在,是匹配到的子串 |
$_ |
參見(jiàn)input |
$* |
參見(jiàn)multiline |
$& |
參見(jiàn)lastMatch |
$+ |
參見(jiàn)lastParen |
$` |
參見(jiàn)leftContext |
$' |
參見(jiàn)rightContext |
constructor |
創(chuàng)建一個(gè)對(duì)象的一個(gè)特殊的函數(shù)原型 |
global |
是否在整個(gè)串中匹配(bool型) |
ignoreCase |
匹配時(shí)是否忽略大小寫(xiě)(bool型) |
input |
被匹配的串 |
lastIndex |
最后一次匹配的索引 |
lastParen |
最后一個(gè)括號(hào)括起來(lái)的子串 |
leftContext |
最近一次匹配以左的子串 |
multiline |
是否進(jìn)行多行匹配(bool型) |
prototype |
允許附加屬性給對(duì)象 |
rightContext |
最近一次匹配以右的子串 |
source |
正則表達(dá)式模式 |
lastIndex |
最后一次匹配的索引
|
|
正則表達(dá)式對(duì)象的方法
方法 |
含義 |
compile |
正則表達(dá)式比較 |
exec |
執(zhí)行查找 |
test |
進(jìn)行匹配 |
toSource |
返回特定對(duì)象的定義(literal representing),其值可用來(lái)創(chuàng)建一個(gè)新的對(duì)象。重載Object.toSource方法得到的。
|
toString |
返回特定對(duì)象的串。重載Object.toString方法得到的。 |
valueOf |
返回特定對(duì)象的原始值。重載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"
〓簡(jiǎn)介〓
字符意義:對(duì)于字符,通常表示按字面意義,指出接著的字符為特殊字符,不作解釋。
例如:/b/匹配字符'b',通過(guò)在b
前面加一個(gè)反斜杠,也就是/b/,則該字符變成特殊字符,表示匹配一個(gè)單詞的分界線(xiàn)。或者:對(duì)于幾個(gè)字符,通常說(shuō)明是特殊的,指出緊接著的字符不是特殊的,而應(yīng)該按字面解釋。例如:*是一個(gè)特殊字符,匹配任意個(gè)字符(包括0個(gè)字符);例如:/a*/意味匹配0個(gè)或多個(gè)a。為了匹配字面上的*,在a前面加一個(gè)反斜杠;例如:/a*/匹配'a*'。
〓正文〓
字符
意義:對(duì)于字符,通常表示按字面意義,指出接著的字符為特殊字符,不作解釋。
例如:/b/匹配字符'b',通過(guò)在b
前面加一個(gè)反斜杠,也就是/b/,則該字符變成特殊字符,表示
匹配一個(gè)單詞的分界線(xiàn)。
或者:
對(duì)于幾個(gè)字符,通常說(shuō)明是特殊的,指出緊接著的字符不是特殊的,而應(yīng)該按字面解釋。
例如:*是一個(gè)特殊字符,匹配任意個(gè)字符(包括0個(gè)字符);例如:/a*/意味匹配0個(gè)或多個(gè)a。
為了匹配字面上的*,在a前面加一個(gè)反斜杠;例如:/a*/匹配'a*'。
字符^
意義:表示匹配的字符必須在最前邊。
例如:/^A/不匹配"an A,"中的'A',但匹配"An A."中最前面的'A'。
字符$
意義:與^類(lèi)似,匹配最末的字符。
例如:/t$/不匹配"eater"中的't',但匹配"eat"中的't'。
字符*
意義:匹配*前面的字符0次或n次。
例如:/bo*/匹配"A ghost booooed"中的'boooo'或"A bird
warbled"中的'b',但不匹配"A goat g
runted"中的任何字符。
字符+
意義:匹配+號(hào)前面的字符1次或n次。等價(jià)于{1,}。
例如:/a+/匹配"candy"中的'a'和"caaaaaaandy."中的所有'a'。
字符?
意義:匹配?前面的字符0次或1次。
例如:/e?le?/匹配"angel"中的'el'和"angle."中的'le'。
字符.
意義:(小數(shù)點(diǎn))匹配除換行符外的所有單個(gè)的字符。
例如:/.n/匹配"nay, an apple is on the
tree"中的'an'和'on',但不匹配'nay'。
字符(x)
意義:匹配'x'并記錄匹配的值。
例如:/(foo)/匹配和記錄"foo
bar."中的'foo'。匹配子串能被結(jié)果數(shù)組中的素[1], ..., [n] 返
回,或被RegExp對(duì)象的屬性$1, ..., $9返回。
字符x|y
意義:匹配'x'或者'y'。
例如:/green|red/匹配"green apple"中的'green'和"red
apple."中的'red'。
字符{n}
意義:這里的n是一個(gè)正整數(shù)。匹配前面的n個(gè)字符。
例如:/a{2}/不匹配"candy,"中的'a',但匹配"caandy,"
中的所有'a'和"caaandy."中前面的兩個(gè)
'a'。
字符{n,}
意義:這里的n是一個(gè)正整數(shù)。匹配至少n個(gè)前面的字符。
例如:/a{2,}不匹配"candy"中的'a',但匹配"caandy"中的所有'a'和"caaaaaaandy."中的所有'a'
字符{n,m}
意義:這里的n和m都是正整數(shù)。匹配至少n個(gè)最多m個(gè)前面的字符。
例如:/a{1,3}/不匹配"cndy"中的任何字符,但匹配 "candy,"中的'a',"caandy," 中的前面兩個(gè)
'a'和"caaaaaaandy"中前面的三個(gè)'a',注意:即使"caaaaaaandy" 中有很多個(gè)'a',但只匹配前面的三
個(gè)'a'即"aaa"。
字符[xyz]
意義:一字符列表,匹配列出中的任一字符。你可以通過(guò)連字符-指出一個(gè)字符范圍。
例如:[abcd]跟[a-c]一樣。它們匹配"brisket"中的'b'和"ache"中的'c'。
字符[^xyz]
意義:一字符補(bǔ)集,也就是說(shuō),它匹配除了列出的字符外的所有東西。 你可以使用連字符-指出一
字符范圍。
例如:[^abc]和[^a-c]等價(jià),它們最早匹配"brisket"中的'r'和"chop."中的'h'。
字符[b]
意義:匹配一個(gè)空格(不要與b混淆)
字符b
意義:匹配一個(gè)單詞的分界線(xiàn),比如一個(gè)空格(不要與[b]混淆)
例如:/bnw/匹配"noonday"中的'no',/wyb/匹配"possibly yesterday."中的'ly'。
字符B
意義:匹配一個(gè)單詞的非分界線(xiàn)
例如:/wBn/匹配"noonday"中的'on',/yBw/匹配"possibly
yesterday."中的'ye'。
字符cX
意義:這里的X是一個(gè)控制字符。匹配一個(gè)字符串的控制字符。
例如:/cM/匹配一個(gè)字符串中的control-M。
字符d
意義:匹配一個(gè)數(shù)字,等價(jià)于[0-9]。
例如:/d/或/[0-9]/匹配"B2 is the suite
number."中的'2'。
字符D
意義:匹配任何的非數(shù)字,等價(jià)于[^0-9]。
例如:/D/或/[^0-9]/匹配"B2 is the suite
number."中的'B'。
字符f
意義:匹配一個(gè)表單符
字符n
意義:匹配一個(gè)換行符
字符r
意義:匹配一個(gè)回車(chē)符
字符s
意義:匹配一個(gè)單個(gè)white空格符,包括空格,tab,form feed,換行符,等價(jià)于[ fnrtv]。
例如:/sw*/匹配"foo bar."中的' bar'。
字符S
意義:匹配除white空格符以外的一個(gè)單個(gè)的字符,等價(jià)于[^ fnrtv]。
例如:/S/w*匹配"foo
bar."中的'foo'。
字符t
意義:匹配一個(gè)制表符
字符v
意義:匹配一個(gè)頂頭制表符
字符w
意義:匹配所有的數(shù)字和字母以及下劃線(xiàn),等價(jià)于[A-Za-z0-9_]。
例如:/w/匹配"apple,"中的'a',"$5.28,"中的'5'和"3D."中的'3'。
字符W
意義:匹配除數(shù)字、字母外及下劃線(xiàn)外的其它字符,等價(jià)于[^A-Za-z0-9_]。
例如:/W/或者/[^$A-Za-z0-9_]/匹配"50%."中的'%'。
字符n
意義:這里的n是一個(gè)正整數(shù)。匹配一個(gè)正則表達(dá)式的最后一個(gè)子串的n的值(計(jì)數(shù)左圓括號(hào))。
例如:/apple(,)sorange1/匹配"apple, orange, cherry, peach."中的'apple, orange',下面
有一個(gè)更加完整的例子。
注意:如果左圓括號(hào)中的數(shù)字比n指定的數(shù)字還小,則n取下一行的八進(jìn)制escape作為描述。
字符ooctal和xhex
意義:這里的ooctal是一個(gè)八進(jìn)制的escape值,而xhex是一個(gè)十六進(jìn)制的escape值,允許在一個(gè)正則表達(dá)式中嵌入ASCII碼。
內(nèi)存模型 (memory model)
內(nèi)存模型描述的是程序中各變量(實(shí)例域、靜態(tài)域和數(shù)組元素)之間的關(guān)系,以及在實(shí)際計(jì)算機(jī)系統(tǒng)中將變量存儲(chǔ)到內(nèi)存和從內(nèi)存取出變量這樣的低層細(xì)節(jié).
不同平臺(tái)間的處理器架構(gòu)將直接影響內(nèi)存模型的結(jié)構(gòu).
在C或C++中, 可以利用不同操作平臺(tái)下的內(nèi)存模型來(lái)編寫(xiě)并發(fā)程序. 但是, 這帶給開(kāi)發(fā)人員的是, 更高的學(xué)習(xí)成本.
相比之下, java利用了自身虛擬機(jī)的優(yōu)勢(shì), 使內(nèi)存模型不束縛于具體的處理器架構(gòu), 真正實(shí)現(xiàn)了跨平臺(tái).
(針對(duì)hotspot jvm, jrockit等不同的jvm, 內(nèi)存模型也會(huì)不相同)
內(nèi)存模型的特征:
a, Visibility 可視性 (多核,多線(xiàn)程間數(shù)據(jù)的共享)
b, Ordering 有序性 (對(duì)內(nèi)存進(jìn)行的操作應(yīng)該是有序的)
java 內(nèi)存模型
(
java memory model
)
根據(jù)Java Language Specification中的說(shuō)明, jvm系統(tǒng)中存在一個(gè)主內(nèi)存(Main Memory或Java Heap Memory),Java中所有變量都儲(chǔ)存在主存中,對(duì)于所有線(xiàn)程都是共享的。
每條線(xiàn)程都有自己的工作內(nèi)存(Working Memory),工作內(nèi)存中保存的是主存中某些變量的拷貝,線(xiàn)程對(duì)所有變量的操作都是在工作內(nèi)存中進(jìn)行,線(xiàn)程之間無(wú)法相互直接訪問(wèn),變量傳遞均需要通過(guò)主存完成。
其中, 工作內(nèi)存里的變量, 在多核處理器下, 將大部分儲(chǔ)存于處理器高速緩存中, 高速緩存在不經(jīng)過(guò)內(nèi)存時(shí), 也是不可見(jiàn)的.
jmm怎么體現(xiàn) 可視性(Visibility) ?
在jmm中, 通過(guò)并發(fā)線(xiàn)程修改變量值, 必須將線(xiàn)程變量同步回主存后, 其他線(xiàn)程才能訪問(wèn)到.
jmm怎么體現(xiàn) 有序性(Ordering) ?
通過(guò)java提供的同步機(jī)制或volatile關(guān)鍵字, 來(lái)保證內(nèi)存的訪問(wèn)順序.
緩存一致性(cache coherency)
什么是緩存一致性?
它是一種管理多處理器系統(tǒng)的高速緩存區(qū)結(jié)構(gòu),其可以保證數(shù)據(jù)在高速緩存區(qū)到內(nèi)存的傳輸中不會(huì)丟失或重復(fù)。(來(lái)自wikipedia)
舉例理解:
假如有一個(gè)處理器有一個(gè)更新了的變量值位于其緩存中,但還沒(méi)有被寫(xiě)入主內(nèi)存,這樣別的處理器就可能會(huì)看不到這個(gè)更新的值.
解決緩存一致性的方法?
a, 順序一致性模型:
要求某處理器對(duì)所改變的變量值立即進(jìn)行傳播, 并確保該值被所有處理器接受后, 才能繼續(xù)執(zhí)行其他指令.
b, 釋放一致性模型: (類(lèi)似jmm cache coherency)
允許處理器將改變的變量值延遲到釋放鎖時(shí)才進(jìn)行傳播.
jmm緩存一致性模型 - "happens-before ordering(先行發(fā)生排序)"
一般情況下的示例程序:
x = 0;
y = 0;
i = 0;
j = 0;
// thread A
y = 1;
x = 1;
// thread B
i = x;
j = y;
在如上程序中, 如果線(xiàn)程A,B在無(wú)保障情況下運(yùn)行, 那么i,j各會(huì)是什么值呢?
答案是, 不確定. (00,01,10,11都有可能出現(xiàn))
這里沒(méi)有使用java同步機(jī)制, 所以 jmm 有序性和可視性 都無(wú)法得到保障.
happens-before ordering(
先行發(fā)生排序)
如何避免這種情況?
排序原則已經(jīng)做到:
a,
在程序順序中,
線(xiàn)程中的每一個(gè)操作, 發(fā)生在當(dāng)前操作后面將要出現(xiàn)的每一個(gè)操作之前.
b, 對(duì)象監(jiān)視器的解鎖發(fā)生在等待獲取對(duì)象鎖的線(xiàn)程之前.
c, 對(duì)volitile關(guān)鍵字修飾的變量寫(xiě)入操作, 發(fā)生在對(duì)該變量的讀取之前.
d,
對(duì)一個(gè)線(xiàn)程的 Thread.start() 調(diào)用 發(fā)生在啟動(dòng)的線(xiàn)程中的所有操作之前.
e, 線(xiàn)程中的所有操作 發(fā)生在從這個(gè)線(xiàn)程的 Thread.join()成功返回的所有其他線(xiàn)程之前.
為了實(shí)現(xiàn)
happends-before ordering原則, java及jdk提供的工具:
a, synchronized關(guān)鍵字
b, volatile關(guān)鍵字
c, final變量
d, java.util.concurrent.locks包(since jdk 1.5)
e, java.util.concurrent.atmoic包(since jdk 1.5)
...
使用了happens-before ordering的例子:
(1) 獲取對(duì)象監(jiān)視器的鎖(lock)
(2) 清空工作內(nèi)存數(shù)據(jù), 從主存復(fù)制變量到當(dāng)前工作內(nèi)存, 即同步數(shù)據(jù) (read and load)
(3) 執(zhí)行代碼,改變共享變量值 (use and assign)
(4) 將工作內(nèi)存數(shù)據(jù)刷回主存 (store and write)
(5) 釋放對(duì)象監(jiān)視器的鎖 (unlock)
注意: 其中4,5兩步是同時(shí)進(jìn)行的.
這邊最核心的就是第二步, 他同步了主內(nèi)存,即前一個(gè)線(xiàn)程對(duì)變量改動(dòng)的結(jié)果,可以被當(dāng)前線(xiàn)程獲知!(利用了happens-before ordering原則)
對(duì)比之前的例子
如果多個(gè)線(xiàn)程同時(shí)執(zhí)行一段未經(jīng)鎖保護(hù)的代碼段,很有可能某條線(xiàn)程已經(jīng)改動(dòng)了變量的值,但是其他線(xiàn)程卻無(wú)法看到這個(gè)改動(dòng),依然在舊的變量值上進(jìn)行運(yùn)算,最終導(dǎo)致不可預(yù)料的運(yùn)算結(jié)果。
經(jīng)典j2ee設(shè)計(jì)模式Double-Checked Locking失效問(wèn)題
雙重檢查鎖定失效問(wèn)題,一直是JMM無(wú)法避免的缺陷之一.了解DCL失效問(wèn)題, 可以幫助我們深入JMM運(yùn)行原理.
要展示DCL失效問(wèn)題, 首先要理解一個(gè)重要概念- 延遲加載(lazy loading).
非單例的單線(xiàn)程延遲加載示例:
class Foo
{
private Resource res = null;
public Resource getResource()
{
// 普通的延遲加載
if (res == null)
res = new Resource();
return res;
}
}
非單例的
多線(xiàn)程延遲加載示例:
Class Foo
{
Private Resource res = null;
Public synchronized
Resource getResource()
{
// 獲取實(shí)例操作使用同步方式, 性能不高
If (res == null) res = new Resource();
return res;
}
}
非單例的
DCL多線(xiàn)程延遲加載示例:
Class Foo
{
Private Resource res = null;
Public Resource getResource()
{
If (res == null)
{
//只有在第一次初始化時(shí),才使用同步方式.
synchronized(this)
{
if(res == null)
{
res = new Resource();
}
}
}
return res;
}
}
Double-Checked Locking看起來(lái)是非常完美的。但是很遺憾,根據(jù)Java的語(yǔ)言規(guī)范,上面的代碼是不可靠的。
出現(xiàn)上述問(wèn)題, 最重要的2個(gè)原因如下:
1, 編譯器優(yōu)化了程序指令, 以加快cpu處理速度.
2, 多核cpu動(dòng)態(tài)調(diào)整指令順序, 以加快并行運(yùn)算能力.
問(wèn)題出現(xiàn)的順序:
1, 線(xiàn)程A, 發(fā)現(xiàn)對(duì)象未實(shí)例化, 準(zhǔn)備開(kāi)始實(shí)例化
2, 由于編譯器優(yōu)化了程序指令, 允許對(duì)象在構(gòu)造函數(shù)未調(diào)用完前, 將
共享變量的引用指向
部分構(gòu)造的對(duì)象, 雖然對(duì)象未完全實(shí)例化, 但已經(jīng)不為null了.
3, 線(xiàn)程B, 發(fā)現(xiàn)部分構(gòu)造的對(duì)象已不是null, 則直接返回了該對(duì)象.
不過(guò), 一些著名的開(kāi)源框架, 包括jive,lenya等也都在使用DCL模式, 且未見(jiàn)一些極端異常.
說(shuō)明, DCL失效問(wèn)題的出現(xiàn)率還是比較低的.
接下來(lái)就是性能與穩(wěn)定之間的選擇了?
DCL的替代
Initialize-On-Demand
:
public class Foo {
// 似有靜態(tài)內(nèi)部類(lèi), 只有當(dāng)有引用時(shí), 該類(lèi)才會(huì)被裝載
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
總結(jié):
多線(xiàn)程編程, 針對(duì)有寫(xiě)操作的變量, 必須 保證其所有引用點(diǎn)與主存中數(shù)據(jù)一致(考慮采用同步或volatile)
.
Executor
提供了管理終止的方法,以及可為跟蹤一個(gè)或多個(gè)異步任務(wù)執(zhí)行狀況而生成 Future
的方法。
可以關(guān)閉 ExecutorService,這將導(dǎo)致其停止接受新任務(wù)。關(guān)閉后,執(zhí)行程序?qū)⒆詈蠼K止,這時(shí)沒(méi)有任務(wù)在執(zhí)行,也沒(méi)有任務(wù)在等待執(zhí)行,并且無(wú)法提交新任務(wù)。
通過(guò)創(chuàng)建并返回一個(gè)可用于取消執(zhí)行和/或等待完成的 Future
,方法 submit 擴(kuò)展了基本方法 Executor.execute(java.lang.Runnable)
。方法 invokeAny 和 invokeAll 是批量執(zhí)行的最常用形式,它們執(zhí)行任務(wù)集合,然后等待至少一個(gè),或全部任務(wù)完成(可使用 ExecutorCompletionService
類(lèi)來(lái)編寫(xiě)這些方法的自定義變體)。
Executors
類(lèi)提供了用于此包中所提供的執(zhí)行程序服務(wù)的工廠方法。
用法示例
下面給出了一個(gè)網(wǎng)絡(luò)服務(wù)的簡(jiǎn)單結(jié)構(gòu),這里線(xiàn)程池中的線(xiàn)程作為傳入的請(qǐng)求。它使用了預(yù)先配置的
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
}
}
壓縮不僅僅可以提高用戶(hù)的下載速度,同時(shí)還可以加密代碼,下面說(shuō)下一個(gè)常用的js壓縮方法:
首先使用dojo的工具shrinksafe(http://shrinksafe.dojotoolkit.org/)壓縮一下,dojo的這個(gè)
工具會(huì)去掉注釋?zhuān)膲嚎s不是簡(jiǎn)單的替換變量,而是利用了mozilla的一個(gè)工具,對(duì)js解析后才壓縮,確保壓縮后的代碼不會(huì)出錯(cuò)。
dojo壓縮后,并不會(huì)減少太多,下一步可以使用http://javascriptcompressor.com/這個(gè)站點(diǎn)進(jìn)行更高層次的壓縮,可惜只能登陸這個(gè)站點(diǎn)再壓縮,只能將你的js代碼復(fù)制的他的文本框,然后等他的壓縮輸出
經(jīng)過(guò)這2步,你的js會(huì)變得既安全,文件又小
關(guān)于JSP頁(yè)面中的pageEncoding和contentType兩種屬性的區(qū)別:
pageEncoding是jsp文件本身的編碼
contentType的charset是指服務(wù)器發(fā)送給客戶(hù)端時(shí)的內(nèi)容編碼
JSP要經(jīng)過(guò)兩次的“編碼”,第一階段會(huì)用pageEncoding,第二階段會(huì)用utf-8至utf-8,第三階段就是由Tomcat出來(lái)的網(wǎng)頁(yè),
用的是contentType。Phontol.com
第一階段是jsp編譯成.java,它會(huì)根據(jù)pageEncoding的設(shè)定讀取jsp,結(jié)果是由指定的編碼方案翻譯成統(tǒng)一的UTF-8
JAVA源碼(即.java),如果pageEncoding設(shè)定錯(cuò)了,或沒(méi)有設(shè)定,出來(lái)的就是中文亂碼。Phontol.com
第二階段是由JAVAC的JAVA源碼至java
byteCode的編譯,不論JSP編寫(xiě)時(shí)候用的是什么編碼方案,經(jīng)過(guò)這個(gè)階段的結(jié)果全部是UTF-8的encoding的java源碼。Phontol.com
JAVAC用UTF-8的encoding讀取java源碼,編譯成UTF-8
encoding的二進(jìn)制碼(即.class),這是JVM對(duì)常數(shù)字串在二進(jìn)制碼(java encoding)內(nèi)表達(dá)的規(guī)范。Phontol.com
第三階段是Tomcat(或其的application
container)載入和執(zhí)行階段二的來(lái)的JAVA二進(jìn)制碼,輸出的結(jié)果,也就是在客戶(hù)端見(jiàn)到的,這時(shí)隱藏在階段一和階段二的參數(shù)contentType就發(fā)揮了功效
contentType的設(shè)定.
pageEncoding 和contentType的預(yù)設(shè)都是 ISO8859-1. 而隨便設(shè)定了其中一個(gè),
另一個(gè)就跟著一樣了(TOMCAT4.1.27是如此). 但這不是絕對(duì)的, 這要看各自JSPC的處理方式.
而pageEncoding不等于contentType, 更有利亞洲區(qū)的文字 CJKV系JSP網(wǎng)頁(yè)的開(kāi)發(fā)和展示, (例pageEncoding=GB2312
不等于 contentType=utf-8)。
在Tomcat中如果在jsp中設(shè)定了pageEncoding,則contentType也跟著設(shè)定成相同的編碼了,但是在resion中就不是,resin中還會(huì)用默認(rèn)的,這點(diǎn)通過(guò)查看編譯后的類(lèi)servlet java文件就可以看到這一點(diǎn),而問(wèn)題恰恰就出在這里,所以,在jsp中,如果是在resin下最好還是明確的單獨(dú)設(shè)定這2個(gè)屬性。
jsp文件不像.java,.java在被編譯器讀入的時(shí)候默認(rèn)采用的是操作系統(tǒng)所設(shè)定的locale所對(duì)應(yīng)的編碼,比如中國(guó)大陸就是GBK,臺(tái)灣就是BIG5或者M(jìn)S950。Phontol.com而一般我們不管是在記事本還是在ue中寫(xiě)代碼,如果沒(méi)有經(jīng)過(guò)特別轉(zhuǎn)碼的話(huà),寫(xiě)出來(lái)的都是本地編碼格式的內(nèi)容。Phontol.com所以編譯器采用的方法剛好可以讓虛擬機(jī)得到正確的資料。Phontol.com
但是jsp文件不是這樣,它沒(méi)有這個(gè)默認(rèn)轉(zhuǎn)碼過(guò)程,但是指定了pageEncoding就可以實(shí)現(xiàn)正確轉(zhuǎn)碼了。Phontol.com
舉個(gè)例子:
<%@ page contentType="text/html;charset=utf-8" %>
|
大都會(huì)打印出亂碼,因?yàn)檩斎氲?#8220;你好”是gbk的,但是服務(wù)器是否正確抓到“你好”不得而知。Phontol.com
但是如果更改為
<%@ page contentType="text/html;charset=utf-8" pageEncoding="GBK"%>
|
這樣就服務(wù)器一定會(huì)是正確抓到“你好”了。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>個(gè)人郵箱登陸</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 內(nèi)容格式:
xx@163.com,xdf.com,xxx,xxx
在firefox3下Components.classes 是不允許直接調(diào)用的,需要加上如下那句粗體的語(yǔ)句才可以
<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里如下設(shè)定,注意黃色部分,很關(guān)鍵
content sample chrome/content/
xpcnativewrappers=no
overlay chrome://browser/content/browser.xul chrome://sample/content/sample.xul
調(diào)用方式:
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>底端對(duì)齊 </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 語(yǔ)言后就會(huì)發(fā)現(xiàn)這樣兩個(gè)詞:反射 (Reflection) 和內(nèi)省 (Introspector) ,經(jīng)常搞不清楚這到底是怎么回事,在什么場(chǎng)合下應(yīng)用以及如何使用?今天把這二者放在一起介紹,因?yàn)樗鼈兌呤窍噍o相成的。
反射
相對(duì)而言,反射比內(nèi)省更容易理解一點(diǎn)。用一句比較白的話(huà)來(lái)概括,反射就是讓你可以通過(guò)名稱(chēng)來(lái)得到對(duì)象 ( 類(lèi),屬性,方法 ) 的技術(shù)。例如我們可以通過(guò)類(lèi)名來(lái)生成一個(gè)類(lèi)的實(shí)例;知道了方法名,就可以調(diào)用這個(gè)方法;知道了屬性名就可以訪問(wèn)這個(gè)屬性的值。
還是寫(xiě)兩個(gè)例子讓大家更直觀的了解反射的使用方法:
引用
//通過(guò)類(lèi)名來(lái)構(gòu)造一個(gè)類(lèi)的實(shí)例
Class cls_str = Class.forName( "java.lang.String" );
// 上面這句很眼熟,因?yàn)槭褂眠^(guò) JDBC 訪問(wèn)數(shù)據(jù)庫(kù)的人都用過(guò) J
Object str = cls_str.newInstance();
// 相當(dāng)于 String str = new String();
//通過(guò)方法名來(lái)調(diào)用一個(gè)方法
String methodName = "length" ;
Method m = cls_str.getMethod(methodName, null );
System.out.println( "length is " + m.invoke(str, null ));
// 相當(dāng)于 System.out.println(str.length());
上面的兩個(gè)例子是比較常用方法。看到上面的例子就有人要發(fā)問(wèn)了:為什么要這么麻煩呢?本來(lái)一條語(yǔ)句就完成的事情干嗎要整這么復(fù)雜?沒(méi)錯(cuò),在上面的例子中確實(shí)沒(méi)有必要這么麻煩。不過(guò)你想像這樣一個(gè)應(yīng)用程序,它支持動(dòng)態(tài)的功能擴(kuò)展,也就是說(shuō)程序不重新啟動(dòng)但是可以自動(dòng)加載新的功能,這個(gè)功能使用一個(gè)具體類(lèi)來(lái)表示。首先我們必須為這些功能定義一個(gè)接口類(lèi),然后我們要求所有擴(kuò)展的功能類(lèi)必須實(shí)現(xiàn)我指定的接口,這個(gè)規(guī)定了應(yīng)用程序和可擴(kuò)展功能之間的接口規(guī)則,但是怎么動(dòng)態(tài)加載呢?我們必須讓?xiě)?yīng)用程序知道要擴(kuò)展的功能類(lèi)的類(lèi)名,比如是 test.Func1 ,當(dāng)我們把這個(gè)類(lèi)名 ( 字符串 ) 告訴應(yīng)用程序后,它就可以使用我們第一個(gè)例子的方法來(lái)加載并啟用新的功能。這就是類(lèi)的反射,請(qǐng)問(wèn)你有別的選擇嗎?
關(guān)于方法的反射建議大家看我的另外一篇文章《 利用 Turbine 的事件映射來(lái)擴(kuò)展 Struts 的功能 》,地址是: http://www.javayou.com/article/CSDN/extend_struts.html 。這篇文章詳細(xì)介紹了如果通過(guò)反射來(lái)擴(kuò)展 Struts 框架的功能。
內(nèi)省
內(nèi)省是 Java 語(yǔ)言對(duì) Bean 類(lèi)屬性、事件的一種缺省處理方法。例如類(lèi) A 中有屬性 name, 那我們可以通過(guò) getName,setName 來(lái)得到其值或者設(shè)置新的值。通過(guò) getName/setName 來(lái)訪問(wèn) name 屬性,這就是默認(rèn)的規(guī)則。 Java 中提供了一套 API 用來(lái)訪問(wèn)某個(gè)屬性的 getter/setter 方法,通過(guò)這些 API 可以使你不需要了解這個(gè)規(guī)則(但你最好還是要搞清楚),這些 API 存放于包 java.beans 中。
一般的做法是通過(guò)類(lèi) Introspector 來(lái)獲取某個(gè)對(duì)象的 BeanInfo 信息,然后通過(guò) BeanInfo 來(lái)獲取屬性的描述器( PropertyDescriptor ),通過(guò)這個(gè)屬性描述器就可以獲取某個(gè)屬性對(duì)應(yīng)的 getter/setter 方法,然后我們就可以通過(guò)反射機(jī)制來(lái)調(diào)用這些方法。下面我們來(lái)看一個(gè)例子,這個(gè)例子把某個(gè)對(duì)象的所有屬性名稱(chēng)和值都打印出來(lái):
引用
/*
* Created on 2004-6-29
*/
package demo;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
/**
* 內(nèi)省演示例子
* @author liudong
*/
public class IntrospectorDemo {
String name;
public static void main(String[] args) throws Exception{
IntrospectorDemo demo = new IntrospectorDemo();
demo.setName( "Winter Lau" );
// 如果不想把父類(lèi)的屬性也列出來(lái)的話(huà),
// 那 getBeanInfo 的第二個(gè)參數(shù)填寫(xiě)父類(lèi)的信息
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 開(kāi)發(fā)框架 Struts 中的 FormBean 就是通過(guò)內(nèi)省機(jī)制來(lái)將表單中的數(shù)據(jù)映射到類(lèi)的屬性上,因此要求 FormBean 的每個(gè)屬性要有 getter/setter 方法。但也并不總是這樣,什么意思呢?就是說(shuō)對(duì)一個(gè) Bean 類(lèi)來(lái)講,我可以沒(méi)有屬性,但是只要有 getter/setter 方法中的其中一個(gè),那么 Java 的內(nèi)省機(jī)制就會(huì)認(rèn)為存在一個(gè)屬性,比如類(lèi)中有方法 setMobile ,那么就認(rèn)為存在一個(gè) mobile 的屬性,這樣可以方便我們把 Bean 類(lèi)通過(guò)一個(gè)接口來(lái)定義而不用去關(guān)心具體實(shí)現(xiàn),不用去關(guān)心 Bean 中數(shù)據(jù)的存儲(chǔ)。比如我們可以把所有的 getter/setter 方法放到接口里定義,但是真正數(shù)據(jù)的存取則是在具體類(lèi)中去實(shí)現(xiàn),這樣可提高系統(tǒng)的擴(kuò)展性。
總結(jié)
將 Java 的反射以及內(nèi)省應(yīng)用到程序設(shè)計(jì)中去可以大大的提供程序的智能化和可擴(kuò)展性。有很多項(xiàng)目都是采取這兩種技術(shù)來(lái)實(shí)現(xiàn)其核心功能,例如我們前面提到的 Struts ,還有用于處理 XML 文件的 Digester 項(xiàng)目,其實(shí)應(yīng)該說(shuō)幾乎所有的項(xiàng)目都或多或少的采用這兩種技術(shù)。在實(shí)際應(yīng)用過(guò)程中二者要相互結(jié)合方能發(fā)揮真正的智能化以及高度可擴(kuò)展性。
另外,以下是SUN的java doc 對(duì)
Introspector的解釋?zhuān)?br />
- 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 會(huì)做編碼轉(zhuǎn)換,F(xiàn)ileInputStream會(huì)忠實(shí)于原始文件數(shù)據(jù)。任何形式的Reader都會(huì)涉及編碼。
BufferedInputStream和BufferedOutputStream
BufferedInputStream:
添加了功能,即緩沖輸入和支持 mark 和 reset 方法的能力。創(chuàng)建 BufferedInputStream
時(shí)即創(chuàng)建了一個(gè)內(nèi)部緩沖區(qū)數(shù)組。讀取或跳過(guò)流中的各字節(jié)時(shí),必要時(shí)可根據(jù)所包含的輸入流再次填充該內(nèi)部緩沖區(qū),一次填充多個(gè)字節(jié)。mark
操作記錄輸入流中的某個(gè)點(diǎn),reset 操作導(dǎo)致在從所包含的輸入流中獲取新的字節(jié)前,再次讀取自最后一次 mark 操作以來(lái)所讀取的所有字節(jié)。
BufferedOutputStream:該類(lèi)實(shí)現(xiàn)緩沖的輸出流。通過(guò)設(shè)置這種輸出流,應(yīng)用程序就可以將各個(gè)字節(jié)寫(xiě)入基礎(chǔ)輸出流中,而不必為每次字節(jié)寫(xiě)入調(diào)用基礎(chǔ)系統(tǒng)。
BufferedReader和FileReader
BufferedReader :由Reader類(lèi)擴(kuò)展而來(lái),提供通用的緩沖方式文本讀取,而且提供了很實(shí)用的readLine,讀取分行文本很適合,BufferedReader是針對(duì)Reader的,不直接針對(duì)文件,也不是只針對(duì)文件讀取。
FileReader
是由java.io.InputStreamReade擴(kuò)展來(lái)的,是針對(duì)文件讀取的。實(shí)際使用時(shí)往往用 BufferedReader
bufferedreader = new BufferedReader(new
FileReader("test.conf"));先建立一個(gè)文件reader,再用BufferedReader讀。
FileInputStream和Reader
FileInputStream:
擴(kuò)展自java.io.InputStream,InputStream提供的是字節(jié)流的讀取,而非文本讀取,這是和Reader類(lèi)的根本區(qū)別。用
Reader讀取出來(lái)的是char數(shù)組或者String ,使用InputStream讀取出來(lái)的是byte數(shù)組。
Reader:Reader
類(lèi)及其子類(lèi)提供的字符流的讀取char(16位),InputStream及其子類(lèi)提供字節(jié)流的讀取byte(8位),所以FileReader類(lèi)是將文
件按字符流的方式讀取,F(xiàn)ileInputStream則按字節(jié)流的方式讀取文件,BufferedReader的作用是提供緩沖,
InputStreamReader可以將讀如stream轉(zhuǎn)換成字符流方式(即reader)是reader和stream之間的橋梁
BufferedInputStream和BufferedOutputStream的一個(gè)例子
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("復(fù)制文件: "+srcFile.length()+"字節(jié)");
while(bufferedInputStream.read(data)!=-1)...{
bufferedOutputStream.write(data);
}
//將緩沖區(qū)中的數(shù)據(jù)全部寫(xiě)出
bufferedOutputStream.flush();
System.out.println("復(fù)制完成");
//顯示輸出BufferedStreamDemo.txt文件的內(nèi)容
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/
通過(guò)使用某種協(xié)議進(jìn)行通信來(lái)完成分布式事務(wù),被稱(chēng)為
兩段式提交。從名字上看,您可能已經(jīng)知道有兩個(gè)階段:
- 第一個(gè)階段,即預(yù)提交:
- 事務(wù)協(xié)調(diào)器給每個(gè)事務(wù)管理器發(fā)送準(zhǔn)備操作的信號(hào)。
- 事務(wù)管理器將操作(通常是數(shù)據(jù)更新)步驟(或細(xì)節(jié))寫(xiě)入事務(wù)日志。如果失敗,事務(wù)管理器使用這些步驟重復(fù)操作。
- 事務(wù)管理器本地創(chuàng)建事務(wù)并通知資源管理器對(duì)資源(例如,數(shù)據(jù)庫(kù)或消息服務(wù)器)執(zhí)行操作。
- 資源管理器執(zhí)行操作并向事務(wù)管理器報(bào)告成功(準(zhǔn)備提交信號(hào))或失敗(準(zhǔn)備回滾)。
- 資源管理器等待事務(wù)管理器進(jìn)一步的指令。
- 事務(wù)管理器向事務(wù)協(xié)調(diào)器報(bào)告成功或失敗。
- 第二階段,即提交階段:在第二階段中,第一階段的結(jié)果將傳送給所有事務(wù)管理器。如果任何事務(wù)管理器報(bào)告失敗,所有的事務(wù)參與者都必須回滾。
- 事務(wù)協(xié)調(diào)器讓所有事務(wù)管理器提交(或回滾)。
- 所有事務(wù)管理器將提交或回滾信息傳遞給其資源管理器。
- 資源管理器將成功或失敗提示返回給事務(wù)管理器。
- 事務(wù)管理器向事務(wù)協(xié)調(diào)器報(bào)告成功或失敗。
【IT168 技術(shù)文檔】很多人對(duì)二級(jí)緩存都不太了解,或者是有錯(cuò)誤的認(rèn)識(shí),我一直想寫(xiě)一篇文章介紹一下hibernate的二級(jí)緩存的,今天終于忍不住了。
我的經(jīng)驗(yàn)主要來(lái)自hibernate2.1版本,基本原理和3.0、3.1是一樣的,請(qǐng)?jiān)徫业念B固不化。
hibernate的session提供了一級(jí)緩存,每個(gè)session,對(duì)同一個(gè)id進(jìn)行兩次load,不會(huì)發(fā)送兩條sql給數(shù)據(jù)庫(kù),但是session關(guān)閉的時(shí)候,一級(jí)緩存就失效了。
二級(jí)緩存是SessionFactory級(jí)別的全局緩存,它底下可以使用不同的緩存類(lèi)庫(kù),比如ehcache、oscache等,需要設(shè)置hibernate.cache.provider_class,我們這里用ehcache,在2.1中就是
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider
如果使用查詢(xún)緩存,加上
hibernate.cache.use_query_cache=true
緩存可以簡(jiǎn)單的看成一個(gè)Map,通過(guò)key在緩存里面找value。
Class的緩存
對(duì)于一條記錄,也就是一個(gè)PO來(lái)說(shuō),是根據(jù)ID來(lái)找的,緩存的key就是ID,value是POJO。無(wú)論list,load還是
iterate,只要讀出一個(gè)對(duì)象,都會(huì)填充緩存。但是list不會(huì)使用緩存,而iterate會(huì)先取數(shù)據(jù)庫(kù)select
id出來(lái),然后一個(gè)id一個(gè)id的load,如果在緩存里面有,就從緩存取,沒(méi)有的話(huà)就去數(shù)據(jù)庫(kù)load。假設(shè)是讀寫(xiě)緩存,需要設(shè)置:
<cache usage="read-write"/>
如果你使用的二級(jí)緩存實(shí)現(xiàn)是ehcache的話(huà),需要配置ehcache.xml
<cache
name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false"
timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true"
/>
其中eternal表示緩存是不是永遠(yuǎn)不超時(shí),timeToLiveSeconds是緩存中每個(gè)元素(這里也就是一個(gè)POJO)的超時(shí)時(shí)間,如果
eternal="false",超過(guò)指定的時(shí)間,這個(gè)元素就被移走了。timeToIdleSeconds是發(fā)呆時(shí)間,是可選的。當(dāng)往緩存里面put
的元素超過(guò)500個(gè)時(shí),如果overflowToDisk="true",就會(huì)把緩存中的部分?jǐn)?shù)據(jù)保存在硬盤(pán)上的臨時(shí)文件里面。
每個(gè)需要緩存的class都要這樣配置。如果你沒(méi)有配置,hibernate會(huì)在啟動(dòng)的時(shí)候警告你,然后使用defaultCache的配置,這樣多個(gè)class會(huì)共享一個(gè)配置。
當(dāng)某個(gè)ID通過(guò)hibernate修改時(shí),hibernate會(huì)知道,于是移除緩存。
這樣大家可能會(huì)想,同樣的查詢(xún)條件,第一次先list,第二次再iterate,就可以使用到緩存了。實(shí)際上這是很難的,因?yàn)槟銦o(wú)法判斷什么時(shí)候是第一
次,而且每次查詢(xún)的條件通常是不一樣的,假如數(shù)據(jù)庫(kù)里面有100條記錄,id從1到100,第一次list的時(shí)候出了前50個(gè)id,第二次
iterate的時(shí)候卻查詢(xún)到30至70號(hào)id,那么30-50是從緩存里面取的,51到70是從數(shù)據(jù)庫(kù)取的,共發(fā)送1+20條sql。所以我一直認(rèn)為
iterate沒(méi)有什么用,總是會(huì)有1+N的問(wèn)題。
(題外話(huà):有說(shuō)法說(shuō)大型查詢(xún)用list會(huì)把整個(gè)結(jié)果集裝入內(nèi)存,很慢,而iterate只select
id比較好,但是大型查詢(xún)總是要分頁(yè)查的,誰(shuí)也不會(huì)真的把整個(gè)結(jié)果集裝進(jìn)來(lái),假如一頁(yè)20條的話(huà),iterate共需要執(zhí)行21條語(yǔ)句,list雖然選擇
若干字段,比iterate第一條select
id語(yǔ)句慢一些,但只有一條語(yǔ)句,不裝入整個(gè)結(jié)果集hibernate還會(huì)根據(jù)數(shù)據(jù)庫(kù)方言做優(yōu)化,比如使用mysql的limit,整體看來(lái)應(yīng)該還是
list快。)
如果想要對(duì)list或者iterate查詢(xún)的結(jié)果緩存,就要用到查詢(xún)緩存了
一個(gè)b好的介紹w3c的網(wǎng)站。
http://www.w3school.com.cn
http://webservices.ctocio.com.cn/wsjavtec/62/7690562.shtml
通常,你需要獲得當(dāng)前日期和計(jì)算一些其他的日期,例如,你的程序可能需要判斷一個(gè)月的第一天或者最后一天。你們大部分人大概都知道怎樣把日期進(jìn)行分割
(年、月、日等),然后僅僅用分割出來(lái)的年、月、日等放在幾個(gè)函數(shù)中計(jì)算出自己所需要的日期!在這篇文 章里,我將告訴你如何使用DATEADD和
DATEDIFF函數(shù)來(lái)計(jì)算出在你的程序中可能你要用到的一些不同日期。
在使用本文中的例子之前,你必須注意以下的問(wèn)題。大部
分可能不是所有例子在不同的機(jī)器上執(zhí)行的結(jié)果可能不一樣,這完全由哪一天是一個(gè)星期的第一天這個(gè)設(shè)置決定。第一天(DATEFIRST)設(shè)定決定了你的系
統(tǒng)使用哪一天作為一周的第一天。所有以下的例 子都是以星期天作為一周的第一天來(lái)建立,也就是第一天設(shè)置為7。假如你的第一天設(shè)置不一樣,你可能需要調(diào)整
這些例子,使它和不同的第一天設(shè)置相符合。你可以通過(guò)@@DATEFIRST函數(shù)來(lái)檢查第一天設(shè)置。
為了理解這些例子,
我們先復(fù)習(xí)一下DATEDIFF和DATEADD函數(shù)。DATEDIFF函數(shù)計(jì)算兩個(gè)日期之間的小時(shí)、天、周、月、年等時(shí)間間隔總數(shù)。DATEADD函數(shù)
計(jì)算一個(gè)日期通過(guò)給時(shí)間間隔加減來(lái)獲得一個(gè)新的日期。要了解更多的DATEDI FF和DATEADD函數(shù)以及時(shí)間間隔可以閱讀微軟聯(lián)機(jī)幫助。
使用DATEDIFF和DATEADD函數(shù)來(lái)計(jì)算日期,和本來(lái)從當(dāng)前日期轉(zhuǎn)換到你需要的日期的考慮方法有點(diǎn)不同。你必須從時(shí)間間隔這個(gè)方面來(lái)考慮。比
如,從當(dāng)前日期到你要得到的日期之間有多少時(shí)間間隔,或者,從今天到某一天(比如1900-1-1)之間有多少時(shí)間間隔,等等。理解怎樣著眼于時(shí)間間隔有
助于你輕松的理解我的不同的日期計(jì)算例子。
一個(gè)月的第一天
第一個(gè)例子,我將告訴你如何從當(dāng)前日期去這個(gè)月的最后一天。請(qǐng)注意:這個(gè)例子以及這篇文章中的其他例子都將只使用DATEDIFF和DATEADD函數(shù)來(lái)計(jì)算我們想要的日期。每一個(gè)例子都將通過(guò)計(jì)算但前的時(shí)間間隔,然后進(jìn)行加減來(lái)得到想要計(jì)算的日期。
這是計(jì)算一個(gè)月第一天的SQL 腳本:
SELECT DATEADD(mm, DATEDIFF(mm,0,getdate()), 0)
我們把這個(gè)語(yǔ)句分開(kāi)來(lái)看看它是如何工作的。最核心的函數(shù)是getdate(),大部分人都知道這個(gè)是返回當(dāng)前的日期和時(shí)間的函數(shù)。下一個(gè)執(zhí)行的函數(shù)
DATEDIFF(mm,0,getdate())是計(jì)算當(dāng)前日期和“1900-01-01 00:00:00.000”這個(gè)日期之間的月數(shù)。記住:時(shí)期
和時(shí)間變量和毫秒一樣是從“1900-01-01 00:00:00.000”開(kāi)始計(jì)算的。這就是為什么你可以在DATEDIFF函數(shù)中指定第一個(gè)時(shí)間表
達(dá)式為“0”。下一個(gè)函數(shù)是DATEADD,增加當(dāng)前日期到“1900-01-01”的月數(shù)。通過(guò)增加預(yù)定義的日期“1900-01-01”和當(dāng)前日期的
月數(shù),我們可以獲得這個(gè)月的第一天。另外,計(jì)算出來(lái)的日期的時(shí)間部分將會(huì)是“00:00:00.000”。
這個(gè)計(jì)算的技巧是先計(jì)算當(dāng)前日期到“1900-01-01”的時(shí)間間隔數(shù),然后把它加到“1900-01-01”上來(lái)獲得特殊的日期,這個(gè)技巧可以用來(lái)計(jì)算很多不同的日期。下一個(gè)例子也是用這個(gè)技巧從當(dāng)前日期來(lái)產(chǎn)生不同的日期。
本周的星期一
這里我是用周(wk)的時(shí)間間隔來(lái)計(jì)算哪一天是本周的星期一。
SELECT DATEADD(wk, DATEDIFF(wk,0,getdate()), 0)
一年的第一天
現(xiàn)在用年(yy)的時(shí)間間隔來(lái)顯示這一年的第一天。
SELECT DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)
季度的第一天
假如你要計(jì)算這個(gè)季度的第一天,這個(gè)例子告訴你該如何做。
SELECT DATEADD(qq, DATEDIFF(qq,0,getdate()), 0)
當(dāng)天的半夜
曾經(jīng)需要通過(guò)getdate()函數(shù)為了返回時(shí)間值截掉時(shí)間部分,就會(huì)考慮到當(dāng)前日期是不是在半夜。假如這樣,這個(gè)例子使用DATEDIFF和DATEADD函數(shù)來(lái)獲得半夜的時(shí)間點(diǎn)。
SELECT DATEADD(dd, DATEDIFF(dd,0,getdate()), 0)
深入DATEDIFF和DATEADD函數(shù)計(jì)算
你可以明白,通過(guò)使用簡(jiǎn)單的DATEDIFF和DATEADD函數(shù)計(jì)算,你可以發(fā)現(xiàn)很多不同的可能有意義的日期。
目前為止的所有例子只是僅僅計(jì)算當(dāng)前的時(shí)間和“1900-01-01”之間的時(shí)間間隔數(shù)量,然后把它加到“1900-01-01”的時(shí)間間隔上來(lái)計(jì)算出
日期。假定你修改時(shí)間間隔的數(shù)量,或者使用不同的時(shí)間間隔來(lái)調(diào)用DATEADD函數(shù),或者減去時(shí)間間隔而不是增加,那么通過(guò)這些小的調(diào)整你可以發(fā)現(xiàn)和多不
同的日期。
這里有四個(gè)例子使用另外一個(gè)DATEADD函數(shù)來(lái)計(jì)算最后一天來(lái)分別替換DATEADD函數(shù)前后兩個(gè)時(shí)間間隔。
上個(gè)月的最后一天
這是一個(gè)計(jì)算上個(gè)月最后一天的例子。它通過(guò)從一個(gè)月的最后一天這個(gè)例子上減去3毫秒來(lái)獲得。有一點(diǎn)要記住,在Sql Server中時(shí)間是精確到3毫秒。這就是為什么我需要減去3毫秒來(lái)獲得我要的日期和時(shí)間。
SELECT dateadd(ms,-3,DATEADD(mm, DATEDIFF(mm,0,getdate()), 0))
計(jì)算出來(lái)的日期的時(shí)間部分包含了一個(gè)Sql Server可以記錄的一天的最后時(shí)刻(“23:59:59:997”)的時(shí)間。
去年的最后一天
連接上面的例子,為了要得到去年的最后一天,你需要在今年的第一天上減去3毫秒。
SELECT dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0))
本月的最后一天
現(xiàn)在,為了獲得本月的最后一天,我需要稍微修改一下獲得上個(gè)月的最后一天的語(yǔ)句。修改需要給用DATEDIFF比較當(dāng)前日期和“1900-01-01”
返回的時(shí)間間隔上加1。通過(guò)加1個(gè)月,我計(jì)算出下個(gè)月的第一天,然后減去3毫秒,這樣就計(jì)算出了這個(gè)月的最后一天。這是計(jì)算本月最后一天的SQL腳本。
SELECT dateadd(ms,-3,DATEADD(mm, DATEDIFF(m,0,getdate())+1, 0))
本年的最后一天
你現(xiàn)在應(yīng)該掌握這個(gè)的做法,這是計(jì)算本年最后一天腳本
SELECT dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate())+1, 0))。
本月的第一個(gè)星期一
好了,現(xiàn)在是最后一個(gè)例子。這里我要計(jì)算這個(gè)月的第一個(gè)星期一。這是計(jì)算的腳本。
select DATEADD(wk, DATEDIFF(wk,0,
dateadd(dd,6-datepart(day,getdate()),getdate())
), 0)
在這個(gè)例子里,我使用了“本周的星期一”的腳本,并作了一點(diǎn)點(diǎn)修改。修改的部分是把原來(lái)腳本中“getdate()”部分替換成計(jì)算本月的第6天,在計(jì)算中用本月的第6天來(lái)替換當(dāng)前日期使得計(jì)算可以獲得這個(gè)月的第一個(gè)星期一。
總結(jié)
我希望這些例子可以在你用DATEADD和DATEDIFF函數(shù)計(jì)算日期時(shí)給你一點(diǎn)啟發(fā)。通過(guò)使用這個(gè)計(jì)算日期的時(shí)間間隔的數(shù)學(xué)方法,我發(fā)現(xiàn)為了顯示兩
個(gè)日期之間間隔的有用歷法是有價(jià)值的。注意,這只是計(jì)算出這些日期的一種方法。要牢記,還有很多方法 可以得到相同的計(jì)算結(jié)果。假如你有其他的方法,那很
不錯(cuò),要是你沒(méi)有,我希望這些例子可以給你一些啟發(fā),當(dāng)你要用DATEADD和DATEDIFF函數(shù)計(jì)算你程序可能要用到的日期時(shí)。
附錄,其他日期處理方法
1)去掉時(shí)分秒
declare @ datetime
set @ = getdate() --’2003-7-1 10:00:00’
SELECT @,DATEADD(day, DATEDIFF(day,0,@), 0)
2)顯示星期幾
select datename(weekday,getdate())
3)如何取得某個(gè)月的天數(shù)
declare @m int
set @m=2 --月份
select datediff(day,’2003-’+cast(@m as varchar)+’-15’ ,’2003-’+cast(@m+1 as varchar)+’-15’)
另外,取得本月天數(shù)
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’)
或者使用計(jì)算本月的最后一天的腳本,然后用DAY函數(shù)區(qū)最后一天
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)一個(gè)季度多少天
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現(xiàn)在正熱得"燙手"。
對(duì)于SOA,目前我聽(tīng)到有兩種說(shuō)法:一種講它是"顛覆性的革命架構(gòu)",一種是"謹(jǐn)慎觀望"。但無(wú)疑,SOA最近幾年發(fā)展得非常快,各主要軟件廠商紛紛高調(diào)跟進(jìn),關(guān)于SOA的報(bào)道可以說(shuō)是不絕于耳。對(duì)"SOA熱",程序員們有的興奮和期待,有的則感到困惑,最近我在金蝶中間件于廣州、上海等城市舉行的"Java俱樂(lè)部"上和程序員們交流時(shí),他們或是以一種朝圣者的表情說(shuō):"以前面向?qū)ο蟮募夹g(shù)過(guò)時(shí)了,SOA時(shí)代來(lái)了",或者一再懇切地追問(wèn)我:"SOA到底是什么?作用是什么?"
那么,SOA是什么?到底能解決什么問(wèn)題、解決得怎樣?我們和客戶(hù)都準(zhǔn)備好了嗎?我給出的答案是"Just Processing,SOA-現(xiàn)在進(jìn)行中"。
SOA到底是什么?
SOA(Service-Oriented Architecture)的定義是面向服務(wù)的架構(gòu),就是說(shuō)將軟件按照功能設(shè)計(jì)成一個(gè)個(gè)服務(wù),這些服務(wù)用標(biāo)準(zhǔn)的方式定義接口、并通過(guò)標(biāo)準(zhǔn)的協(xié)議進(jìn)行調(diào)用。SOA所定義的接口和調(diào)用方式是獨(dú)立于編程語(yǔ)言和運(yùn)行平臺(tái)的,廣義上講SOA可以基于不同的底層技術(shù)實(shí)現(xiàn),比如CORBA和Web Services。但CORBA由于過(guò)于復(fù)雜和臃腫已很少使用,所以目前所說(shuō)的SOA絕大多數(shù)是基于Web Services技術(shù)實(shí)現(xiàn)。在Web Services的實(shí)現(xiàn)方式下,SOA服務(wù)的接口用XML進(jìn)行定義。
在SOA架構(gòu)下,軟件開(kāi)發(fā)從業(yè)務(wù)流程分析開(kāi)始,使用組件化業(yè)務(wù)建模的方法識(shí)別和分析各種業(yè)務(wù)模型,將各種實(shí)踐融入其中,在這個(gè)基礎(chǔ)上建立用例,用例直接產(chǎn)生BPEL,這些BPEL則可以被融入一個(gè)服務(wù)整合框架中,其描述了各種服務(wù)的信息,從而把ESB上的各個(gè)模塊統(tǒng)一起來(lái),形成一個(gè)巨大的服務(wù)倉(cāng)。
這樣,SOA甚至是所有軟件人員的一個(gè)夢(mèng):將中間層再進(jìn)行抽離,在中間層作一個(gè)跨技術(shù)架構(gòu)的元數(shù)據(jù)和業(yè)務(wù)邏輯,使之成為跨技術(shù)架構(gòu)的、可長(zhǎng)期繼承、并不斷積累的企業(yè)業(yè)務(wù)庫(kù)和最寶貴的信息資產(chǎn),也就是面向服務(wù)的組件庫(kù),而且這個(gè)服務(wù)組件庫(kù)也可以被其它企業(yè)復(fù)用,且不依賴(lài)于任何一種技術(shù)架構(gòu)。夸張一點(diǎn)說(shuō),如果所有軟件企業(yè)都使用SOA架構(gòu),那么世界軟件業(yè)將會(huì)發(fā)生徹底的改變。顯然,這樣一個(gè)框架不是一種產(chǎn)品,也不僅僅是一種技術(shù),而是一種解決問(wèn)題的方法論。
SOA可能應(yīng)用的兩個(gè)場(chǎng)景及現(xiàn)有問(wèn)題
那么,SOA要解決的問(wèn)題是什么?我認(rèn)為,從技術(shù)本質(zhì)上講,SOA可能應(yīng)用于兩個(gè)場(chǎng)景:第一種是業(yè)務(wù)互通互聯(lián);第二種是封閉交易系統(tǒng),即將元數(shù)據(jù)和業(yè)務(wù)邏輯抽離,形成可復(fù)用。舉個(gè)例子,在第一種場(chǎng)景中,當(dāng)不同企業(yè)之間的業(yè)務(wù)需要相互調(diào)用,這時(shí)就可能采用SOA技術(shù);在第二種場(chǎng)景中,在企業(yè)內(nèi)部需要將系統(tǒng)進(jìn)行遷移時(shí),利用SOA技術(shù)定義的原有數(shù)據(jù)和業(yè)務(wù)流程,可以很快完成。
無(wú)疑,SOA是一個(gè)偉大的思想,它試圖定義一個(gè)大家(各種軟件廠商)都"認(rèn)"的、都"遵循"的法則,大家都使用這樣的方法來(lái)進(jìn)行互聯(lián)互通,從而實(shí)現(xiàn)無(wú)界限的聯(lián)通,以及服務(wù)組件庫(kù)的繼承和復(fù)用,解放無(wú)效和重復(fù)勞動(dòng)。打一個(gè)不那么恰當(dāng)?shù)谋扔鳎拖袢祟?lèi)的語(yǔ)言一樣。SOA或許就像《圣經(jīng)》中那個(gè)著名的"通天塔"的故事:人們用同一種語(yǔ)言交流產(chǎn)生的威力是如此之大,以至于他們?cè)诎捅葌悗缀跻蕹梢粋€(gè)"通天塔",直達(dá)上帝所在的天庭。
但是,在SOA應(yīng)用的兩個(gè)場(chǎng)景中,現(xiàn)存的問(wèn)題同樣也是明顯的:
第一種場(chǎng)景:業(yè)務(wù)互聯(lián)互通,就是應(yīng)用系統(tǒng)互聯(lián)。業(yè)務(wù)互聯(lián),與其說(shuō)是技術(shù)問(wèn)題,不如講是業(yè)務(wù)問(wèn)題,例如ERP、CRM的異步整合,數(shù)據(jù)層面整合都不能很好將兩個(gè)系統(tǒng)整合,SOA僅僅是一種實(shí)現(xiàn)工具之一,整合效果并不會(huì)好不到那里去。我們可以說(shuō),在沒(méi)有其他選項(xiàng)之前,SOA是一種最"不壞"的方式,但它并不能解決所有的問(wèn)題,實(shí)際上EAI的牽涉面很廣,而我們知道,有些問(wèn)題并不是單純靠技術(shù)就能解決的。
第二種場(chǎng)景:封閉交易系統(tǒng),缺點(diǎn)是性能慢,而且基于Web Services的交易沒(méi)有形成明確的規(guī)范。使用XML作信息交互比較慢是大家都承認(rèn)的,性能問(wèn)題將對(duì)SOA的發(fā)展造在一定的阻力。同時(shí)SOA規(guī)范本身沒(méi)有完善,比如Transaction規(guī)范還在不斷完善,而且Web Service多年來(lái)收效甚微。總的來(lái)說(shuō),SOA現(xiàn)在還處在一個(gè)發(fā)展階段,很多標(biāo)準(zhǔn)還在制定,不同廠商間還存在不兼容的現(xiàn)象,因此SOA還不能說(shuō)已經(jīng)是一個(gè)成熟的技術(shù),還需要時(shí)間的檢驗(yàn),還在"進(jìn)行中"。當(dāng)然,金蝶中間件作為JCP組織成員,也會(huì)推動(dòng)SOA規(guī)范在J2EE平臺(tái)上的實(shí)現(xiàn)。
中國(guó)用戶(hù)的現(xiàn)實(shí)選擇之惑
在憧憬SOA技術(shù)可能帶來(lái)的前景之余,我們不得不回過(guò)頭來(lái)冷靜地說(shuō):SOA和我們大家的共同客戶(hù)――中國(guó)企業(yè)還有距離。
中國(guó)信息化進(jìn)程與歐美不同,大量的基礎(chǔ)業(yè)務(wù)系統(tǒng)還沒(méi)建立起來(lái),整合需求并不如想象的那么大。從我們對(duì)客戶(hù)的了解,發(fā)現(xiàn)很少有客戶(hù)有SOA的需求。簡(jiǎn)單地總結(jié)就是,互通無(wú)基礎(chǔ),以新建系統(tǒng)為主,需求并不強(qiáng)烈。而歐美市場(chǎng)大量業(yè)務(wù)系統(tǒng)已建立起來(lái)需要整合,從這個(gè)角度講,SOA是適用于他們的。同時(shí),在成功案例極少的前提下,SOA還處于培育期,新建封閉交易系統(tǒng)使用SOA技術(shù)還是有一定風(fēng)險(xiǎn)的。
一項(xiàng)新技術(shù)需要市場(chǎng)的消化,大型企業(yè)出于保護(hù)企業(yè)投資,不會(huì)輕易地轉(zhuǎn)移到新的技術(shù)平臺(tái);而即使像J2EE這樣成熟的技術(shù)經(jīng)過(guò)了這么多年的發(fā)展,也不敢說(shuō)占有統(tǒng)治地位的市場(chǎng)份額。SOA還需要整個(gè)IT界的用戶(hù)和供應(yīng)商共同促進(jìn)。
中國(guó)信息化需要什么樣的技術(shù)架構(gòu)、能夠接受什么樣的成本價(jià)位?這不僅僅是我們的客戶(hù)需要考慮,我們軟件廠商要比客戶(hù)考慮得更清楚、更進(jìn)一步。在這個(gè)充滿(mǎn)變數(shù)的激烈競(jìng)爭(zhēng)市場(chǎng),只有冷靜務(wù)實(shí)才能生存、發(fā)展。
From:http://blog.csdn.net/Apusicyuan/archive/2007/03/16/1531424.aspx
解析SOA十大設(shè)計(jì)原則 公共接口要明確界限
作者: 佚名, 出處:CSDN, 責(zé)任編輯: 包春林,
2008-04-23 05:00
日前國(guó)外網(wǎng)站報(bào)道介紹了面向服務(wù)架構(gòu)(SOA)的基本原則,提出了公共接口與內(nèi)部實(shí)現(xiàn)要有明確界限等原則。雖然這些原則并不是絕對(duì)的真理,但可作為一個(gè)應(yīng)用開(kāi)發(fā)參考。
一、明確的邊界
通過(guò)跨越定義明確的邊界進(jìn)行顯式消息傳遞,服務(wù)得以彼此交互。有時(shí)候,跨越服務(wù)邊界可能要耗費(fèi)很大的成本,這要視地理、信任或執(zhí)行因素而定。邊界是指服務(wù)的公共接口與其內(nèi)部專(zhuān)用實(shí)現(xiàn)之間的界線(xiàn)。服務(wù)的邊界通過(guò) WSDL 發(fā)布,可能包括說(shuō)明特定服務(wù)之期望的聲明。
二、服務(wù)共享和約和架構(gòu),不是類(lèi)
服務(wù)交互應(yīng)當(dāng)只以服務(wù)的策略、架構(gòu)和基于合約的行為為基礎(chǔ)。服務(wù)的合約通常使用 WSDL 定義,而服務(wù)聚合的合約則可以使用 BPEL 定義(進(jìn)而,對(duì)聚合的每個(gè)服務(wù)使用 WSDL)。服務(wù)使用者將依靠服務(wù)的合約來(lái)調(diào)用服務(wù)及與服務(wù)交互。鑒于這種依賴(lài)性,服務(wù)合約必須長(zhǎng)期保持穩(wěn)定。在利用 XML 架構(gòu) (xsd:any) 和 SOAP 處理模型(可選標(biāo)頭)的可擴(kuò)展性的同時(shí),合約的設(shè)計(jì)應(yīng)盡可能明確。
三、策略驅(qū)動(dòng)
盡管它往往被認(rèn)為是最不為人所了解的原則,但對(duì)于實(shí)現(xiàn)靈活的 Web 服務(wù),它或許是最有力的。單純依靠 WSDL 無(wú)法交流某些業(yè)務(wù)交互要求。可以使用策略表達(dá)式將結(jié)構(gòu)兼容性(交流的內(nèi)容)與語(yǔ)義兼容性(如何交流消息或者將消息交流給誰(shuí))分隔開(kāi)來(lái)。
四、自治
服務(wù)是獨(dú)立進(jìn)行部署、版本控制和管理的實(shí)體。開(kāi)發(fā)人員應(yīng)避免對(duì)服務(wù)邊界之間的空間進(jìn)行假設(shè),因?yàn)榇丝臻g比邊界本身更容易改變。
五、采用可傳輸?shù)膮f(xié)議格式,而不是API
通常,服務(wù)提供商基于某種傳輸協(xié)議(例如HTTP)提供服務(wù),而服務(wù)消費(fèi)者只能通過(guò)另一種不同的協(xié)議(比如MQ)通信。因此,也許需要在服務(wù)提供商與消費(fèi)者之間建立一座異步起動(dòng)同步運(yùn)行的連接橋梁,超越HTTP和Java Messaging Service消息服務(wù)(JMS)等協(xié)議.從技術(shù)角度講,Java Messaging Service消息服務(wù)(JMS)并不是一種傳輸協(xié)議,而是一組供應(yīng)商中立(vendor-neutral)的通信APIs。
六、面向文檔
消息被構(gòu)造為“純文本的”XML文檔(換句話(huà)說(shuō),數(shù)據(jù)的格式只對(duì)XML有意義)。 消息通常用于傳輸業(yè)務(wù)文檔,比如購(gòu)買(mǎi)訂單、發(fā)票和提單。這種交互類(lèi)型與同步消息排隊(duì)系統(tǒng)的兼容性很好,比如MQ Series、MSMQ、JMS、TIBCO、IMS等等。
七、松耦合
服務(wù)之間要求最小的依賴(lài)性,只要求它們之間能夠相互知曉。
八、符合標(biāo)準(zhǔn)
當(dāng)通過(guò)Web的服務(wù)實(shí)現(xiàn)時(shí),最原始的(基本的)面向服務(wù)的架構(gòu)(SOA)的模型僅僅提供了很低程度上的關(guān)于可靠性、安全性以及事務(wù)管理的標(biāo)準(zhǔn)化機(jī)制。第二代的技術(shù)條件和框架,如WS-ReliableMessaging規(guī)范、 WS-Security規(guī)范和WS-Coordination規(guī)范 (與WS-AtomicTransaction規(guī)范和WS-BusinessActivity規(guī)范相聯(lián)系),它們?cè)噲D以工業(yè)標(biāo)準(zhǔn)的方式定位存在的缺陷。
九、獨(dú)立軟件供應(yīng)商
向SOA的轉(zhuǎn)變正在深刻改變了經(jīng)濟(jì)現(xiàn)實(shí)。客戶(hù)們會(huì)期待更合理的費(fèi)用以及不必重新進(jìn)行投資就能改進(jìn)業(yè)務(wù)的能力。因此,獨(dú)立軟件供應(yīng)商沒(méi)有選擇,只能使自己的業(yè)務(wù)更加靈活,以期讓自己的客戶(hù)也變得同樣靈活。于是,面向服務(wù)不僅是簡(jiǎn)單的在現(xiàn)有的、緊耦合的、復(fù)雜的、不靈活的以及非組件化的業(yè)務(wù)功能上添加基于標(biāo)準(zhǔn)的接口。更重要的是,為了兌現(xiàn)SOA的承諾,獨(dú)立軟件供應(yīng)商必須改變他們構(gòu)建、打包、銷(xiāo)售、交付、管理和支持自身產(chǎn)品的方式。
十、元數(shù)據(jù)驅(qū)動(dòng)
開(kāi)發(fā)元數(shù)據(jù)本身并不是元數(shù)據(jù)驅(qū)動(dòng)應(yīng)用程序的本意。使用元數(shù)據(jù)來(lái)驅(qū)動(dòng)服務(wù)在系統(tǒng)邊界的傳播是一個(gè)更為正確的方法。
一個(gè)事務(wù)處理的屬性有:Required,RequiresNew,Mandatory,NotSupported,Supports,Never.
1、Required:當(dāng)客戶(hù)端運(yùn)行一個(gè)事務(wù)處理并調(diào)用EJB的一個(gè)方法,這個(gè)方法執(zhí)行客戶(hù)端的事務(wù)處理;當(dāng)客戶(hù)端沒(méi)有啟動(dòng)一個(gè)事務(wù)處理,則EJB容器在執(zhí)行這個(gè)方法之前啟動(dòng)一個(gè)新的事務(wù)處理.
2、RequiresNew:當(dāng)客戶(hù)端運(yùn)行一個(gè)事務(wù)處理并調(diào)用EJB的一個(gè)方法時(shí),容器管理器做如下操作:
(1) 懸掛客戶(hù)端的事務(wù)處理;
(2) 開(kāi)始一個(gè)新的事務(wù)處理;
(3) 調(diào)用方法;
(4) 當(dāng)方法結(jié)束,恢復(fù)客戶(hù)端的事物處理.
當(dāng)客戶(hù)端沒(méi)有啟動(dòng)一個(gè)事務(wù)處理,容器管理器在執(zhí)行這個(gè)方法之前啟動(dòng)一個(gè)新的事務(wù)處理.
3、Mandatory: 當(dāng)客戶(hù)端運(yùn)行一個(gè)事務(wù)處理并調(diào)用EJB的一個(gè)方法,這個(gè)方法在客戶(hù)端的事務(wù)處理范圍內(nèi)被執(zhí)行; 當(dāng)客戶(hù)端沒(méi)有啟動(dòng)一個(gè)事務(wù)處理,容器管理器將會(huì)拋錯(cuò)(TransactionRequiredException);
4、NotSupported: 當(dāng)客戶(hù)端運(yùn)行一個(gè)事務(wù)處理并調(diào)用EJB的一個(gè)方法,容器管理器在調(diào)用方法之前終止客戶(hù)端的事務(wù)處理,當(dāng)方法執(zhí)行完,再恢復(fù)客戶(hù)端的事務(wù)處理; 當(dāng)客戶(hù)端沒(méi)有啟動(dòng)一個(gè)事務(wù)處理,容器管理器在調(diào)用方法時(shí)不啟動(dòng)事務(wù)處理.
5、Supports: 當(dāng)客戶(hù)端運(yùn)行一個(gè)事務(wù)處理并調(diào)用EJB的一個(gè)方法,在運(yùn)行方法時(shí)執(zhí)行客戶(hù)端的事務(wù)處理; 當(dāng)客戶(hù)端沒(méi)有啟動(dòng)一個(gè)事務(wù)處理,容器管理器在調(diào)用方法時(shí)不啟動(dòng)事務(wù)處理.
6、Never: 當(dāng)客戶(hù)端運(yùn)行一個(gè)事務(wù)處理并調(diào)用EJB的一個(gè)方法,容器管理器將拋出一個(gè)錯(cuò)誤(RemoteException); 當(dāng)客戶(hù)端沒(méi)有啟動(dòng)一個(gè)事務(wù)處理,容器管理器在調(diào)用方法時(shí)不啟動(dòng)事務(wù)處理.
在jbuilder中,缺省是Required;
第一個(gè)ejb可以是 Required,這個(gè)ejb調(diào)用的那個(gè)ejb方法如果想在一個(gè)
事務(wù)上下文中,我覺(jué)得可能采用Mandatory,方式比較好。如果它們不在一個(gè)事務(wù)上下文中,就會(huì)拋錯(cuò)(TransactionRequiredException),是一個(gè)上下文,就沒(méi)有問(wèn)題
幾乎每個(gè)做過(guò)Web開(kāi)發(fā)的人都問(wèn)過(guò),到底元素的ID和Name有什么區(qū)別阿?為什么有了ID還要有Name呢?而同樣我們也可以得到最classical的答案:ID就像是一個(gè)人的身份證號(hào)碼,而Name就像是他的名字,ID顯然是唯一的,而Name是可以重復(fù)的。
上周我也遇到了ID和Name的問(wèn)題,在頁(yè)面里輸入了一個(gè)input type="hidden",只寫(xiě)了一個(gè)ID='SliceInfo',賦值后submit,在后臺(tái)用Request.Params["SliceInfo"]卻怎么也去不到值。后來(lái)恍然大悟因該用Name來(lái)標(biāo)示,于是在input里加了個(gè)Name='SliceInfo',就一切ok了。
第一段里對(duì)于ID和Name的解答說(shuō)的太籠統(tǒng)了,當(dāng)然那個(gè)解釋對(duì)于ID來(lái)說(shuō)是完全對(duì)的,它就是Client端HTML元素的Identity。而Name其實(shí)要復(fù)雜的多,因?yàn)镹ame有很多種的用途,所以它并不能完全由ID來(lái)代替,從而將其取消掉。
具體用途有:
用途1: 作為可與服務(wù)器交互數(shù)據(jù)的HTML元素的服務(wù)器端的標(biāo)示,比如input、select、textarea、和button等。我們可以在服務(wù)器端根據(jù)其N(xiāo)ame通過(guò)Request.Params取得元素提交的值。
用途2: HTML元素Input type='radio'分組,我們知道radio button控件在同一個(gè)分組類(lèi),check操作是mutex的,同一時(shí)間只能選中一個(gè)radio,這個(gè)分組就是根據(jù)相同的Name屬性來(lái)實(shí)現(xiàn)的。
用途3: 建立頁(yè)面中的錨點(diǎn),我們知道link是獲得一個(gè)頁(yè)面超級(jí)鏈接,如果不用href屬性,而改用Name,如:,我們就獲得了一個(gè)頁(yè)面錨點(diǎn)。
用途4: 作為對(duì)象的Identity,如Applet、Object、Embed等元素。比如在Applet對(duì)象實(shí)例中,我們將使用其N(xiāo)ame來(lái)引用該對(duì)象。
用途5: 在IMG元素和MAP元素之間關(guān)聯(lián)的時(shí)候,如果要定義IMG的熱點(diǎn)區(qū)域,需要使用其屬性u(píng)semap,使usemap="#name"(被關(guān)聯(lián)的MAP元素的Name)。
用途6: 某些特定元素的屬性,如attribute,和param。例如為Object定義參數(shù)
顯然這些用途都不是能簡(jiǎn)單的使用ID來(lái)代替掉的,所以HTML元素的ID和Name的卻別并不是身份證號(hào)碼和姓名這樣的區(qū)別,它們更本就是不同作用的東西。
當(dāng)然HTML元素的Name屬性在頁(yè)面中也可以起那么一點(diǎn)ID的作用,因?yàn)樵贒HTML對(duì)象樹(shù)中,我們可以使用document.getElementsByName來(lái)獲取一個(gè)包含頁(yè)面中所有指定Name元素的對(duì)象數(shù)組。
在這里順便說(shuō)一下,要是頁(yè)面中有n(n>1)個(gè)HTML元素的ID都相同了怎么辦?在DHTML對(duì)象中怎么引用他們呢?如果我們使用ASPX頁(yè)面,這樣的情況是不容易發(fā)生的,因?yàn)閍spnet進(jìn)程在處理aspx頁(yè)面時(shí)根本就不允許有ID非唯一,這是頁(yè)面會(huì)被拋出異常而不能被正常的render。要是不是動(dòng)態(tài)頁(yè)面,我們硬要讓ID重復(fù)那IE怎么搞呢?
這個(gè)時(shí)候我們還是可以繼續(xù)使用document.getElementById獲取對(duì)象,只不過(guò)我們只能獲取ID重復(fù)的那些對(duì)象中在HTML Render時(shí)第一個(gè)出現(xiàn)的對(duì)象。而這時(shí)重復(fù)的ID會(huì)在引用時(shí)自動(dòng)變成一個(gè)數(shù)組,ID重復(fù)的元素按Render的順序依次存在于數(shù)組中。
程序題:我想啟動(dòng)一個(gè)線(xiàn)程執(zhí)行特定的任務(wù),任務(wù)的具體執(zhí)行內(nèi)容定義在TheRunnable類(lèi)中(實(shí)現(xiàn)了java.lang.Runnable接口):
TheRunnable theRunnable = new TheRunnable();
以下哪個(gè)語(yǔ)句可用于啟動(dòng)theRunnable任務(wù)線(xiàn)程:_____
a) theRunnable.run();
b) theRunnable.start();
c) Thread thread = new Thread(theRunnable); thread.run();
d) Thread thread = new Thread(theRunnable); thread.start();
前言
全國(guó)青少年信息學(xué)(計(jì)算機(jī))奧林匹克競(jìng)賽常常要用到許多經(jīng)典算法,比如約瑟夫問(wèn)題、螺旋方陣、漢諾塔、八皇后問(wèn)題等,而 螺旋方陣問(wèn)題是其中較為常用的一種。這類(lèi)問(wèn)題的算法分析對(duì)于計(jì)算機(jī)圖形學(xué)、解析幾何中的相關(guān)問(wèn)題都有一定的啟發(fā)性。盡管現(xiàn)有算法已取得了令人振奮的成績(jī), 但依然具有一定的片面性,或者說(shuō)過(guò)于復(fù)雜。實(shí)際上,這個(gè)問(wèn)題有不同的解決算法,鑒于這個(gè)問(wèn)題具有一定的典型性,本文針對(duì)信息學(xué)奧林匹克競(jìng)賽這一問(wèn)題進(jìn)行了 全面系統(tǒng)的分析、歸納,從不同的角度對(duì)這個(gè)問(wèn)題的算法進(jìn)行分析并通過(guò)程序?qū)崿F(xiàn)。使讀者對(duì)這個(gè)問(wèn)題在算法選擇上有更大的余地,從而避免算法的單一性,同時(shí)對(duì) 于類(lèi)似相關(guān)問(wèn)題的解決也有一定的啟發(fā)和幫助。
2 問(wèn)題的描述與分析
關(guān)于螺旋方陣的輸出主要是指將一些數(shù)據(jù)或符號(hào)按照一定的順序輸出到計(jì)算機(jī)的屏幕上或者是輸出到一個(gè)指定的文件中去,輸出的幾種常見(jiàn)情況如下圖(為簡(jiǎn)單起見(jiàn),以輸出5階的數(shù)字螺旋方陣為例):
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由外及里順時(shí)針;圖2由外及里逆時(shí)針;圖3由里及外順時(shí)針;圖4由里及外逆時(shí)針
在實(shí)際應(yīng)用中,輸出的內(nèi)容可以不盡相同。在上面的圖1至圖4中,按螺旋順序輸出的數(shù)顯然有一定的規(guī)律,而實(shí)際輸出的順序往往不是按照螺旋順序,通常是將上圖中的數(shù)據(jù)按行(或按列)輸出,因此這類(lèi)問(wèn)題的關(guān)鍵在于如何將有規(guī)律的數(shù)據(jù)與實(shí)際輸出時(shí)的先后順序?qū)?yīng)起來(lái)。下面采用不同的算法來(lái)實(shí)現(xiàn)。
3 采用不同算法解決螺旋方陣的輸出
3.1非遞歸算法
3.1.1 “海龜”算法(順時(shí)針,由外及里)
參照海龜行走的做法,用一對(duì)變量A,B模擬海龜頭的方向,根據(jù)屏幕坐標(biāo)的特點(diǎn),A、B的取值和“海龜頭”方向有這樣的關(guān)系:(0,1)表示向右;(0, -1)表示向左;(-1,0)表示向上;(1,0)表示向下;用另一對(duì)變量X,Y模擬海龜位置,“海龜”每前進(jìn)一步,它的新位置即為X=X+A,Y=Y+B;要海龜向右轉(zhuǎn),就改變A、B的值,根據(jù)數(shù)學(xué)知識(shí)可以得出具體的變換公式是:C=A;A=B;B=-C。下面用自然語(yǔ)言對(duì)算法進(jìn)行描述:讓海龜先走n步,然后右轉(zhuǎn),再走n-1步,再右轉(zhuǎn),再走n-1步,再右轉(zhuǎn),再走n-2步,再右轉(zhuǎn),再走n-2步……如此類(lèi)推,直到海龜前進(jìn)的步數(shù)為0時(shí)停止;而每當(dāng)“海龜”前進(jìn)1步,就在它位置上顯示一個(gè)數(shù)字,那么前進(jìn)n步即重復(fù)執(zhí)行“X:=X+A,Y:=Y+B”語(yǔ)句n次。但如何讓下兩個(gè)循環(huán)的重復(fù)次數(shù)都為n-1呢?解決的方法是:循環(huán)n次后,讓n的值減少0.5,然后再轉(zhuǎn)回執(zhí)行同樣的循環(huán)。擴(kuò)展到顯示n位數(shù),則須留n列的位置,也就是說(shuō),海龜水平方向每次得前進(jìn)n步,才有足夠的位置顯示大一點(diǎn)的數(shù)字方陣,需把Y=Y+B改成Y=Y+n*B就行了。“海龜”算法的優(yōu)點(diǎn)是簡(jiǎn)潔清晰。
3.1.2 “分割”算法(逆時(shí)針,由外及里)
設(shè)螺旋方陣對(duì)應(yīng)的一般二維數(shù)組如下:
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
按逆時(shí)針?lè)较驈耐庀騼?nèi),一層層給下標(biāo)變量賦值,由于階數(shù)n的任意性,需考慮以下幾個(gè)問(wèn)題:層數(shù)k與階數(shù)n的關(guān)系式,n由用戶(hù)輸入,k根據(jù)n來(lái)計(jì)算;定義變量value,賦值時(shí)讓其自增;分析每層矩形四條邊元素的下標(biāo)變化規(guī)律,將方陣元素按逆時(shí)針?lè)较蚍殖伤膫€(gè)部分:方陣左半邊(三列),方陣下半邊(二行),方陣右半邊(兩列),方陣上半邊(二行)。
具體算法思想:以5階方陣為例,可判斷 k=[(n+1)/2]=3,用循環(huán)控制產(chǎn)生的層數(shù),語(yǔ)句為for(k=0,k <(n+1)/2;k++)。
Step1:找出方陣左半邊列規(guī)律:列下標(biāo)正好是層數(shù)k的值,行下標(biāo)在第一列從0變到4,第二列從1變到3,在第三列從2變到2,故推導(dǎo)出n階螺旋方陣左半邊由外到內(nèi)的列循環(huán)結(jié)構(gòu):for(i=k;i <n-k;i++) mat[i][k]=value++;此循環(huán)執(zhí)行一次,產(chǎn)生一列元素,循環(huán)執(zhí)行的次數(shù)由外循環(huán)來(lái)控制。
Step2:找出方陣下半邊行規(guī)律:行下標(biāo)從4變到3,每層取值為n―k―1;列下標(biāo)由外到內(nèi)第一行從1變到4(a40已產(chǎn)生),第二行(a30 、a31已產(chǎn)生)從2變到3,第三行只有一個(gè)元素a22,故推導(dǎo)出n階螺旋方陣下半邊行循環(huán)結(jié)構(gòu):for(i=k+1;i <n-k;i++) mat[n-k-1][i]=value++;
Step3:找出方陣右半邊列規(guī)律:行下標(biāo)第一列從3變化到0(a44已產(chǎn)生),第二列從2變到1(a43、a33、a03已產(chǎn)生),可推斷行的初值為n-k-2;列下標(biāo)沒(méi)變化,兩列的下標(biāo)分別為4、3,故推斷出右半邊的列可由下列循環(huán)結(jié)構(gòu)完成:for(i=n-k-2;i >=k;i--) mat[i][n-k-1]=value++;
Step4:找出方陣上半邊行規(guī)律:已經(jīng)產(chǎn)生了的元素不能再重新賦值,而行下標(biāo)可用層次k來(lái)表示,列下標(biāo)與右半邊行下標(biāo)變化規(guī)律一樣,由此推斷出上半邊的行可由下列循環(huán)結(jié)構(gòu)完成:for(i=n-k-2;i >k;i--) mat[k][i]=value++。
當(dāng)k取一個(gè)值時(shí),以上四個(gè)循環(huán)依序各產(chǎn)生一列或一行元素,由此產(chǎn)生一層元素,當(dāng)k在變化范圍[0…(n+1)/2]內(nèi)依次取值時(shí),四個(gè)循環(huán)輪流執(zhí)行,一個(gè)數(shù)字螺旋方陣就這樣生成了。
3.2 遞歸算法
分析圖五容易看出,當(dāng)由外及里順時(shí)針旋轉(zhuǎn)時(shí),最外層數(shù)據(jù)輸出后,內(nèi)層的圖形只不過(guò)是層數(shù)減少了,即問(wèn)題的規(guī)模變小了,但問(wèn)題的性質(zhì)沒(méi)有發(fā)生變化,新問(wèn)題和原問(wèn)題仍然可以采用相同的解法。所以這一問(wèn)題完全可以采用遞歸的方法來(lái)求解。具體的算法描述如下。
Step1:初始化。把需要輸出的數(shù)據(jù)放入一維數(shù)組,設(shè)為b[1..n*n]。因?yàn)槭莕階方陣,所以全部元素共有n2個(gè),輸出b[1]到b[n*n]的順序是方陣順時(shí)針旋轉(zhuǎn)的順序。
Step2:把b數(shù)組中的每個(gè)元素放入到二維數(shù)組a[i][j](圖5)中去,如b[1]放入a[0][0]中,b[2]放入a[0][1]中,……,b[6]放入a[1][4]中……,其它元素依次放入。
Step3:按行輸出數(shù)組元素a[i][j]即可。
上述算法中,難點(diǎn)在于如何將b數(shù)組放入到a[i][j]數(shù)組對(duì)應(yīng)的分量中去。為此,對(duì)step2進(jìn)行求精并使用遞歸來(lái)解決。具體做法:將數(shù)組a初始化為0。設(shè)置變量direction作為方向標(biāo)志。當(dāng)direction為1、2、3、4時(shí),分別表示向右、向下、向左、向上。并編寫(xiě)如下的遞歸子程序walk(x,y,direction,k)。其中參數(shù)x,y表示數(shù)組的下標(biāo)。k是計(jì)數(shù)器。當(dāng) 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 算法實(shí)現(xiàn)
限于篇幅,本文僅給出遞歸算法的主要程序段(pascal語(yǔ)言)
procedure walk(x,y,direction,k:integer);
begin
if k>n*n then 按行輸出a數(shù)組;
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 結(jié)束語(yǔ)
關(guān)于螺旋方陣的輸出算法主要有上述幾種,其他幾種方陣的輸出,可以仿照上述的算法分析加以實(shí)現(xiàn)。相對(duì)而言,遞 歸算法較為簡(jiǎn)潔,但是時(shí)間復(fù)雜度要高一些,對(duì)于輸出高階螺旋方陣時(shí),時(shí)間很長(zhǎng)。另外在空間復(fù)雜度方面,采用數(shù)組這種數(shù)據(jù)結(jié)構(gòu),顯然有一定的局限性,如果使 用鏈表來(lái)存儲(chǔ),將會(huì)盡可能地避免空間不足的現(xiàn)象。另外,上述問(wèn)題也可以使用一個(gè)模板式的子程序來(lái)完成,這時(shí)要求輸入的參數(shù)要包括:從外還是從里螺旋、順時(shí) 針還是逆時(shí)針,起點(diǎn)坐標(biāo)等參數(shù),對(duì)于從里向外螺旋時(shí),還要考慮螺旋方陣的階數(shù)是奇數(shù)還是偶數(shù),分別給予不同的處理。
本篇文章來(lái)源于 義烏信息技術(shù)教研網(wǎng) 原文鏈接:http://www.ywhs.net/itedu/html/aosaifudao/mingshifudao/20071125/47.html
Java最初是在瀏覽器和客戶(hù)端機(jī)器中粉墨登場(chǎng)的。當(dāng)時(shí),很多人質(zhì)疑它是否適合做服務(wù)器端的開(kāi)發(fā)。現(xiàn)在,隨著對(duì)Java2平臺(tái)企業(yè)版(J2EE)第三方支持的增多,Java被廣泛接納為開(kāi)發(fā)企業(yè)級(jí)服務(wù)器端解決方案的首選平臺(tái)之一。
J2EE平臺(tái)由一整套服務(wù)(Services)、應(yīng)用程序接口(APIs)和協(xié)議構(gòu)成,它對(duì)開(kāi)發(fā)基于Web的多層應(yīng)用提供了功能支持。
在本文中我將解釋支撐J2EE的13種核心技術(shù):JDBC, JNDI, EJBs, RMI, JSP, Java servlets, XML, JMS, Java IDL, JTS, JTA, JavaMail 和 JAF,同時(shí)還將描述在何時(shí)、何處需要使用這些技術(shù)。當(dāng)然,我還要介紹這些不同的技術(shù)之間是如何交互的。
此外,為了讓您更好地感受J2EE的真實(shí)應(yīng)用,我將在WebLogic應(yīng)用服務(wù)器,來(lái)自BEA Systems公司的一種廣為應(yīng)用的產(chǎn)品環(huán)境下來(lái)介紹這些技術(shù)。不論對(duì)于WebLogic應(yīng)用服務(wù)器和J2EE的新手,還是那些想了解J2EE能帶來(lái)什么好處的項(xiàng)目管理者和系統(tǒng)分析員,相信本文一定很有參考價(jià)值。
宏觀印象: 分布式結(jié)構(gòu)和J2EE
過(guò)去,二層化應(yīng)用 -- 通常被稱(chēng)為client/server應(yīng)用 -- 是大家談?wù)摰淖疃嗟摹T诤芏嗲闆r下,服務(wù)器提供的惟一服務(wù)就是數(shù)據(jù)庫(kù)服務(wù)。在這種解決方案中,客戶(hù)端程序負(fù)責(zé)數(shù)據(jù)訪問(wèn)、實(shí)現(xiàn)業(yè)務(wù)邏輯、用合適的樣式顯示結(jié)果、彈出預(yù)設(shè)的用戶(hù)界面、接受用戶(hù)輸入等。client/server結(jié)構(gòu)通常在第一次部署的時(shí)候比較容易,但難于升級(jí)或改進(jìn),而且經(jīng)常基于某種專(zhuān)有的協(xié)議,通常是某種數(shù)據(jù)庫(kù)協(xié)議。它使得重用業(yè)務(wù)邏輯和界面邏輯非常困難。更重要的是,在Web時(shí)代,二層化應(yīng)用通常不能體現(xiàn)出很好的伸縮性,因而很難適應(yīng)Internet的要求。
Sun設(shè)計(jì)J2EE的部分起因就是想解決二層化結(jié)構(gòu)的缺陷。于是,J2EE定義了一套標(biāo)準(zhǔn)來(lái)簡(jiǎn)化N層企業(yè)級(jí)應(yīng)用的開(kāi)發(fā)。它定義了一套標(biāo)準(zhǔn)化的組件,并為這些組件提供了完整的服務(wù)。J2EE還自動(dòng)為應(yīng)用程序處理了很多實(shí)現(xiàn)細(xì)節(jié),如安全、多線(xiàn)程等。
用J2EE開(kāi)發(fā)N層應(yīng)用包括將二層化結(jié)構(gòu)中的不同層面切分成許多層。一個(gè)N層化應(yīng)用A能夠?yàn)橐韵碌拿糠N服務(wù)提供一個(gè)分開(kāi)的層:
顯示:在一個(gè)典型的Web應(yīng)用中,客戶(hù)端機(jī)器上運(yùn)行的瀏覽器負(fù)責(zé)實(shí)現(xiàn)用戶(hù)界面。
動(dòng)態(tài)生成顯示: 盡管瀏覽器可以完成某些動(dòng)態(tài)內(nèi)容顯示,但為了兼容不同的瀏覽器,這些動(dòng)態(tài)生成工作應(yīng)該放在Web服務(wù)器端進(jìn)行,使用JSP、Servlets,或者XML(可擴(kuò)展標(biāo)記語(yǔ)言)和(可擴(kuò)展樣式表語(yǔ)言)。
業(yè)務(wù)邏輯:業(yè)務(wù)邏輯適合用Session EJBs(后面將介紹)來(lái)實(shí)現(xiàn)。
數(shù)據(jù)訪問(wèn):數(shù)據(jù)訪問(wèn)適合用Entity EJBs(后面將介紹)和JDBC來(lái)實(shí)現(xiàn)。
后臺(tái)系統(tǒng)集成: 同后臺(tái)系統(tǒng)的集成可能需要用到許多不同的技術(shù),至于何種最佳需要根據(jù)后臺(tái)系統(tǒng)的特征而定。
您可能開(kāi)始詫異:為什么有這么多的層?事實(shí)上,多層方式可以使企業(yè)級(jí)應(yīng)用具有很強(qiáng)的伸縮性,它允許每層專(zhuān)注于特定的角色。例如,讓W(xué)eb服務(wù)器負(fù)責(zé)提供頁(yè)面,應(yīng)用服務(wù)器處理應(yīng)用邏輯,而數(shù)據(jù)庫(kù)服務(wù)器提供數(shù)據(jù)庫(kù)服務(wù)。
由于J2EE建立在Java2平臺(tái)標(biāo)準(zhǔn)版(J2SE)的基礎(chǔ)上,所以具備了J2SE的所有優(yōu)點(diǎn)和功能。包括“編寫(xiě)一次,到處可用”的可移植性、通過(guò)JDBC訪問(wèn)數(shù)據(jù)庫(kù)、同原有企業(yè)資源進(jìn)行交互的CORBA技術(shù),以及一個(gè)經(jīng)過(guò)驗(yàn)證的安全模型。在這些基礎(chǔ)上,J2EE又增加了對(duì)EJB(企業(yè)級(jí)Java組件)、Java servlets、Java服務(wù)器頁(yè)面(JSPs)和XML技術(shù)的支持。
分布式結(jié)構(gòu)與WebLogic應(yīng)用服務(wù)器
J2EE提供了一個(gè)框架--一套標(biāo)準(zhǔn)API--用于開(kāi)發(fā)分布式結(jié)構(gòu)的應(yīng)用,這個(gè)框架的實(shí)際實(shí)現(xiàn)留給了第三方廠商。部分廠商只是專(zhuān)注于整個(gè)J2EE架構(gòu)中的的特定組件,例如Apache的Tomcat提供了對(duì)JSP和servlets的支持,BEA系統(tǒng)公司則通過(guò)其WebLogic應(yīng)用服務(wù)器產(chǎn)品為整個(gè)J2EE規(guī)范提供了一個(gè)較為完整的實(shí)現(xiàn)。
WebLogic服務(wù)器已使建立和部署伸縮性較好的分布式應(yīng)用的過(guò)程大為簡(jiǎn)化。WebLogic和J2EE代你處理了大量常規(guī)的編程任務(wù),包括提供事務(wù)服務(wù)、安全領(lǐng)域、可靠的消息、名字和目錄服務(wù)、數(shù)據(jù)庫(kù)訪問(wèn)和連接池、線(xiàn)程池、負(fù)載平衡和容錯(cuò)處理等。
通過(guò)以一種標(biāo)準(zhǔn)、易用的方式提供這些公共服務(wù),象WebLogic服務(wù)器這樣的產(chǎn)品造就了具有更好伸縮性和可維護(hù)性的應(yīng)用系統(tǒng),使其為大量的用戶(hù)提供了增長(zhǎng)的可用性。
J2EE技術(shù)
在接下來(lái)的部分里,我們將描述構(gòu)成J2EE的各種技術(shù),并且了解WebLogic服務(wù)器是如何在一個(gè)分布式應(yīng)用中對(duì)它們進(jìn)行支持的。最常用的J2EE技術(shù)應(yīng)該是JDBC、JNDI、EJB、JSP和servlets,對(duì)這些我們將作更仔細(xì)的考察。
Java Database Connectivity (JDBC)
JDBC API以一種統(tǒng)一的方式來(lái)對(duì)各種各樣的數(shù)據(jù)庫(kù)進(jìn)行存取。和ODBC一樣,JDBC為開(kāi)發(fā)人員隱藏了不同數(shù)據(jù)庫(kù)的不同特性。另外,由于JDBC建立在Java的基礎(chǔ)上,因此還提供了數(shù)據(jù)庫(kù)存取的平臺(tái)獨(dú)立性。
JDBC定義了4種不同的驅(qū)動(dòng)程序,現(xiàn)分述如下:
類(lèi)型 1: JDBC-ODBC Bridge
在JDBC出現(xiàn)的初期,JDBC-ODBC橋顯然是非常有實(shí)用意義的,通過(guò)JDBC-ODBC橋,開(kāi)發(fā)人員可以使用JDBC來(lái)存取ODBC數(shù)據(jù)源。不足的是,他需要在客戶(hù)端安裝ODBC驅(qū)動(dòng)程序,換句話(huà)說(shuō),必須安裝Microsoft Windows的某個(gè)版本。使用這一類(lèi)型你需要犧牲JDBC的平臺(tái)獨(dú)立性。另外,ODBC驅(qū)動(dòng)程序還需要具有客戶(hù)端的控制權(quán)限。
類(lèi)型 2: JDBC-native driver bridge
JDBC本地驅(qū)動(dòng)程序橋提供了一種JDBC接口,它建立在本地?cái)?shù)據(jù)庫(kù)驅(qū)動(dòng)程序的頂層,而不需要使用ODBC。 JDBC驅(qū)動(dòng)程序?qū)?duì)數(shù)據(jù)庫(kù)的API從標(biāo)準(zhǔn)的JDBC調(diào)用轉(zhuǎn)換為本地調(diào)用。使用此類(lèi)型需要犧牲JDBC的平臺(tái)獨(dú)立性,還要求在客戶(hù)端安裝一些本地代碼。
類(lèi)型 3: JDBC-network bridge
JDBC網(wǎng)絡(luò)橋驅(qū)動(dòng)程序不再需要客戶(hù)端數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序。它使用網(wǎng)絡(luò)上的中間服務(wù)器來(lái)存取數(shù)據(jù)庫(kù)。這種應(yīng)用使得以下技術(shù)的實(shí)現(xiàn)有了可能,這些技術(shù)包括負(fù)載均衡、連接緩沖池和數(shù)據(jù)緩存等。由于第3種類(lèi)型往往只需要相對(duì)更少的下載時(shí)間,具有平臺(tái)獨(dú)立性,而且不需要在客戶(hù)端安裝并取得控制權(quán),所以很適合于Internet上的應(yīng)用。
類(lèi)型 4: Pure Java driver
第4種類(lèi)型通過(guò)使用一個(gè)純Java數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序來(lái)執(zhí)行數(shù)據(jù)庫(kù)的直接訪問(wèn)。此類(lèi)型實(shí)際上在客戶(hù)端實(shí)現(xiàn)了2層結(jié)構(gòu)。要在N-層結(jié)構(gòu)中應(yīng)用,一個(gè)更好的做法是編寫(xiě)一個(gè)EJB,讓它包含存取代碼并提供一個(gè)對(duì)客戶(hù)端具有數(shù)據(jù)庫(kù)獨(dú)立性的服務(wù)。
WebLogic服務(wù)器為一些通常的數(shù)據(jù)庫(kù)提供了JDBC驅(qū)動(dòng)程序,包括Oracle, Sybase, Microsoft SQL Server以及Informix。它也帶有一種JDBC驅(qū)動(dòng)程序用于Cloudscape,這是一種純Java的DBMS,WebLogic服務(wù)器中帶有該數(shù)據(jù)庫(kù)的評(píng)估版本。
以下讓我們看一個(gè)實(shí)例。
JDBC實(shí)例
在這個(gè)例子中我們假定你已經(jīng)在Cloudscape中建立了一個(gè)PhoneBook數(shù)據(jù)庫(kù),并且包含一個(gè)表,名為 CONTACT_TABLE ,它帶有2個(gè)字段:NAME 和 PHONE。 開(kāi)始的時(shí)候先裝載Cloudscape JDBC driver,并請(qǐng)求 driver manager得到一個(gè)對(duì)PhoneBook Cloudscape數(shù)據(jù)庫(kù)的連接。通過(guò)這一連接,我們可以構(gòu)造一個(gè) Statement 對(duì)象并用它來(lái)執(zhí)行一個(gè)簡(jiǎn)單的SQL查詢(xún)。最后,用循環(huán)來(lái)遍歷結(jié)果集的所有數(shù)據(jù),并用標(biāo)準(zhǔn)輸出將NAME和PHONE字段的內(nèi)容進(jìn)行輸出。
創(chuàng)建新表:
create table tabname(col1 type1 [not null] [primary key],col2 type2 [not null],..)
根據(jù)已有的表創(chuàng)建新表:
A:create table tab_new like tab_old
B:create table tab_new as select col1,col2… from tab_old definition only
actionMessage怎么能保存到session中哪!!太占用服務(wù)器資源了。防止刷新比較好的辦法是利用token來(lái)解決就可以了阿:
就你的情況來(lái)看我給你舉個(gè)例子
在Action中的add方法中,我們需要將Token值明確的要求保存在頁(yè)面中,只需增加一條語(yǔ)句:saveToken(request);,如下所示:
public ActionForward add(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
//前面的處理省略
saveToken(request);
//轉(zhuǎn)發(fā)到需要錄入信息的頁(yè)面
return mapping.findForward("add");
}
在Action的insert方法中,我們根據(jù)表單中的Token值與服務(wù)器端的Token值比較,如下所示:
//處理信息錄入的action
public ActionForward insert(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
if (isTokenValid(request, true)) {
// 表單不是重復(fù)提交正常執(zhí)行
} else {
//表單重復(fù)提交
saveToken(request);
//給客戶(hù)端提示錯(cuò)誤,當(dāng)然這里也就是你把ActionMessages保存到request范圍內(nèi),然后forward到錯(cuò)誤頁(yè)面
}
}
執(zhí)行的流程:add(Action)->信息錄入頁(yè)面(jsp)->insert(Action)
綜上,其實(shí)你選擇重定向到頁(yè)面無(wú)非就是為了讓request失效保證不能重復(fù)提交,而恰恰你的錯(cuò)誤信息又是保存到了request范圍內(nèi)了,所以呵呵出現(xiàn)問(wèn)題了,利用token來(lái)解決這個(gè)問(wèn)題吧
了,至于token我再lz解釋一下:
Struts的Token機(jī)制能夠很好的解決表單重復(fù)提交的問(wèn)題,基本原理是:服務(wù)器端在處理到達(dá)的請(qǐng)求之前,會(huì)將請(qǐng)求中包含的令牌值與保存在當(dāng)前用戶(hù)會(huì)話(huà)中的令牌值進(jìn)行比較,看是否匹配。在處理完該請(qǐng)求后,且在答復(fù)發(fā)送給客戶(hù)端之前,將會(huì)產(chǎn)生一個(gè)新的令牌,該令牌除傳給客戶(hù)端以外,也會(huì)將用戶(hù)會(huì)話(huà)中保存的舊的令牌進(jìn)行替換。這樣如果用戶(hù)回退到剛才的提交頁(yè)面并再次提交的話(huà),客戶(hù)端傳過(guò)來(lái)的令牌就和服務(wù)器端的令牌不一致,從而有效地防止了重復(fù)提交的發(fā)生。
這時(shí)其實(shí)也就是兩點(diǎn),第一:你需要在請(qǐng)求中有這個(gè)令牌值,請(qǐng)求中的令牌值如何保存,其實(shí)就和我們平時(shí)在頁(yè)面中保存一些信息是一樣的,通過(guò)隱藏字段來(lái)保存,保存的形式如: 〈input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae"〉,這個(gè)value是TokenProcessor類(lèi)中的generateToken()獲得的,是根據(jù)當(dāng)前用戶(hù)的session id和當(dāng)前時(shí)間的long值來(lái)計(jì)算的。第二:在客戶(hù)端提交后,我們要根據(jù)判斷在請(qǐng)求中包含的值是否和服務(wù)器的令牌一致,因?yàn)榉?wù)器每次提交都會(huì)生成新的Token,所以,如果是重復(fù)提交,客戶(hù)端的Token值和服務(wù)器端的Token值就會(huì)不一致。
http://www.oracle.com/technology/sample_code/tech/java/codesnippet/webservices/attachment/index.html
http://www.ibm.com/developerworks/xml/library/x-tippass.html