??xml version="1.0" encoding="utf-8" standalone="yes"?> q是一个世界范围内都存在的问题Q所以,Java提供了世界性的解决Ҏ。本文描q的Ҏ是用于处理中文的Q但是,推而广之,对于处理世界上其它国家和地区的语a同样适用?/p>
汉字是双字节的。所谓双字节是指一个双字要占用两个BYTE的位|(?6位)Q分别称为高位和低位。中国规定的汉字~码为GB2312Q这是强制性的Q目前几乎所有的能处理中文的应用E序都支持GB2312。GB2312包括了一二汉字?区符P高位?xa1?xfeQ低位也是从0xa1?xfeQ其中,汉字的编码范围ؓ0xb0a1?xf7fe?/p>
另外有一U编码,叫做GBKQ但q是一份规范,不是强制的。GBK提供?0902个汉字,它兼容GB2312Q编码范围ؓ0x8140?xfefe。GBK中的所有字W都可以一一映射到Unicode 2.0?/p>
在不久的来Q中国会颁布另一U标准:GB18030-2000QGBK2KQ。它收录了藏、蒙{少数民族的字型Q从Ҏ上解决了字位不的问题。注意:它不再是定长的。其二字节部份与GBK兼容Q四字节部分是扩充的字符、字形。它的首字节和第三字节从0x81?xfeQ二字节和第四字节从0x30?x39?/p>
本文不打介lUnicodeQ有兴趣的可以浏?#8220;http://www.unicode.org/”查看更多的信息。Unicode有一个特性:它包括了世界上所有的字符字Ş。所以,各个地区的语a都可以徏立与Unicode的映关p,而Java正是利用了这一点以辑ֈ异种语言之间的{换?/p>
在JDK中,与中文相关的~码有: ? JDK中与中文相关的编码列?/font>
]]>
Strust拦截器改q了Strust对Action的操作能?增加了拦截器Ҏ和IoCҎ?
通过分析另外的WEB框架,比如:WebWork 2/XWork,Strust拦截器的目的是把其它WEB框架最好的Ҏ整合到STRUTS?Strust拦截器支持struts1.1, 按照BSD许可发行.
2.特点
Action 拦截
WW2 操作风格
支持 regular ?Tiles
包括使用Strust拦截器修改过的Strust例子
3.使用Ҏ:
把Strust拦截器配|ؓ一个struts插g,可以在需要的M地方调用.
4.配置struts插g:
把Strust拦截器配|ؓ一个struts插g,只需要修?Struts 配置文g可以了,修改后的配置文g.一般看h像这U样?
<plug-in className="net.sf.struts.saif.SAIFPlugin">
<set-property property="interceptor-config" value="/WEB-INF/interceptor-config.xml" />
</plug-in>
5.拦截器的配置
在interceptor-config.xml文g中定义了所有拦?当然可以是另外的M文g?. q个文g包含拦截定义和它们应该如何被使用.
从两个方面来定义 Struts Actions拦截:
globally and by Action. When the Action is requested, first any global interceptors will be applied, then Action-specific interceptors.
The following interceptors are included in SAIF:
Included interceptors Class Description
net.sf.struts.saif.ComponentInterceptor Performs inversion of control functionality. Sets any components the Action has defined it needs.
This is an example of an interceptor configuration file:
<interceptor-config>
<interceptor name="componentInterceptor" type="net.sf.struts.saif.ComponentInterceptor"/>
<interceptor name="testInterceptor" type="net.sf.struts.saif.TestInterceptor"/>
<default-interceptors>
<interceptor name="componentInterceptor"/>
</default-interceptors>
<action type="org.apache.struts.webapp.example.EditRegistrationAction">
<interceptor name="testInterceptor"/>
</action>
</interceptor-config>
Interceptor Implementation
Interceptors can perform actions before and after a Struts Action is called. To write an interceptor, simple implement the net.sf.struts.saif.ActionInterceptor interface and implement the beforeAction() and afterAction() methods.
This is an example of an interceptor implementation:
public class TestInterceptor implements ActionInterceptor
{
public void beforeAction(Action action, ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
{
log.debug("beforeAction called");
}
public void afterAction(Action action, ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
{
log.debug("afterAction called");
}
private Log log = LogFactory.getLog(TestInterceptor.class);
}
Contact
Please contact Lars Hoss or Don Brown with comments, bug reports, and suggestions.
]]>
~码名称
说明
ASCII
7位,与ascii7相同
ISO8859-1
8-位,?8859_1,ISO-8859-1,ISO_8859-1,latin1...{相?/td>
GB2312-80
16位,与gb2312,gb2312-1980,EUC_CN,euccn,1381,Cp1381, 1383, Cp1383, ISO2022CN,ISO2022CN_GB...{相?/td>
GBK
与MS936相同Q注意:区分大小?/td>
UTF8
与UTF-8相同
GB18030
与cp1392?392相同Q目前支持的JDK很少
在实际编E时Q接触得比较多的是GB2312QGBKQ和ISO8859-1?/p>
Z么会?#8220;?”?/strong>
上文说过Q异U语a之间的{换是通过Unicode来完成的。假设有两种不同的语aA和BQ{换的步骤为:先把A转化为UnicodeQ再把Unicode转化为B?/p>
举例说明。有GB2312中有一个汉?#8220;?#8221;Q其~码?#8220;C0EE”Q欲转化为ISO8859-1~码。步骤ؓQ先?#8220;?#8221;字{化ؓUnicodeQ得?#8220;674E”Q再?#8220;674E”转化为ISO8859-1字符。当Ӟq个映射不会成功Q因为ISO8859-1中根本就没有?#8220;674E”对应的字W?/p>
当映不成功Ӟ问题发生了Q当从某语言向Unicode转化Ӟ如果在某语言中没有该字符Q得到的是Unicode的代?#8220;\uffffd”Q?#8220;\u”表示是Unicode~码Q)。而从Unicode向某语言转化Ӟ如果某语a没有对应的字W,则得到的?#8220;0x3f”Q?#8220;?”Q。这是“?”的由来?/p>
例如Q把字符buf =“0x80 0x40 0xb0 0xa1”q行new String(buf, "gb2312")操作Q得到的l果?#8220;\ufffd\u554a”Q再println出来Q得到的l果是“??#8221;Q因?#8220;0x80 0x40”是GBK中的字符Q在GB2312中没有?/p>
再如Q把字符串String="\u00d6\u00ec\u00e9\u0046\u00bb\u00f9"q行new String (buf.getBytes("GBK"))操作Q得到的l果?#8220;3fa8aca8a6463fa8b4”Q其中,“\u00d6”?#8220;GBK”中没有对应的字符Q得?#8220;3f”Q?#8220;\u00ec”对应着“a8ac”Q?#8220;\u00e9”对应着“a8a6”Q?#8220;0046”对应着“46”Q因是ASCII字符Q,“\u00bb”没找刎ͼ得到“3f”Q最后,“\u00f9”对应着“a8b4”。把q个字符串println一下,得到的结果是“?ìéF?ù”。看到没Q这里ƈ不全是问P因ؓGBK与Unicode映射的内容中除了汉字外还有字W,本例是最好的明证?/p>
所以,在汉字{码时Q如果发生错乱,得到的不一定都是问号噢Q不q,错了l究是错了,50步和100步ƈ没有质的差别?/p>
或者会问:如果源字W集中有Q而Unicode中没有,l果会如何?回答是不知道。因为我手头没有能做q个试的源字符集。但有一Ҏ肯定的,那就是源字符集不够规范。在Java中,如果发生q种情况Q是会抛出异常的?/p>
什么是UTF
UTFQ是Unicode Text Format的羃写,意ؓUnicode文本格式。对于UTFQ是q样定义的:
Q?Q如果Unicode?6位字W的?位是0Q则用一个字节表C,q个字节的首位是“0”Q剩下的7位与原字W中的后7位相同,?#8220;\u0034”Q?000 0000 0011 0100Q,?#8220;34” (0011 0100)表示Q(与源Unicode字符是相同的Q;
Q?Q如果Unicode?6位字W的?位是0Q则?个字节表C,首字节是“110”开_后面?位与源字W中除去?个零后的最?位相同;W二个字节以“10”开_后面?位与源字W中的低6位相同。如“\u025d”Q?000 0010 0101 1101Q,转化后ؓ“c99d”Q?100 1001 1001 1101Q;
Q?Q如果不W合上述两个规则Q则用三个字节表C。第一个字节以“1110”开_后四位ؓ源字W的高四位;W二个字节以“10”开_后六位ؓ源字W中间的六位Q第三个字节?#8220;10”开_后六位ؓ源字W的低六位;?#8220;\u9da7”Q?001 1101 1010 0111Q,转化?#8220;e9b6a7”Q?110 1001 1011 0110 1010 0111Q;
可以q么描述JAVAE序中Unicode与UTF的关p,虽然不绝对:字符串在内存中运行时Q表CؓUnicode代码Q而当要保存到文g或其它介质中LQ用的是UTF。这个{化过E是由writeUTF和readUTF来完成的?/p>
好了Q基性的差不多了Q下面进入正题?/p>
先把q个问题x是一个黑匣子。先看黑匣子的一U表C:
input(charsetA)-Qprocess(Unicode)-Qoutput(charsetB)
单,q就是一个IPO模型Q即输入、处理和输出。同L内容要经q?#8220;从charsetA到unicode再到charsetB”的{化?/p>
再看二表示Q?/p>
SourceFile(jsp,java)-Qclass-Qoutput
在这个图中,可以看出Q输入的是jsp和java源文Ӟ在处理过E中Q以Class文g体,然后输出。再l化CU表C:
jsp-Qtemp file-Qclass-Qbrowser,os console,db
app,servlet-Qclass-Qbrowser,os console,db
q个囑ְ更明白了。Jsp文g先生成中间的Java文gQ再生成Class。而Servlet和普通App则直接编译生成Class。然后,从Class再输出到览器、控制台或数据库{?/p>
JSPQ从源文件到Class的过E?/strong>
Jsp的源文g是以“.jsp”l尾的文本文件。在本节中,阐qJSP文g的解释和~译q程Qƈ跟踪其中的中文变化?/p>
1、JSP/Servlet引擎提供的JSP转换工具QjspcQ搜索JSP文g中用Q?@ page contentType ="text/html; charset=QJsp-charsetQ?%Q中指定的charset。如果在JSP文g中未指定QJsp-charsetQ,则取JVM中的默认讄file.encodingQ一般情况下Q这个值是ISO8859-1Q?/p>
2、jspc用相当于“javac –encoding QJsp-charsetQ?#8221;的命令解释JSP文g中出现的所有字W,包括中文字符和ASCII字符Q然后把q些字符转换成Unicode字符Q再转化成UTF格式Q存为JAVA文g。ASCII码字W{化ؓUnicode字符时只是简单地在前面加“00”Q如“A”Q{化ؓ“\u0041”Q不需要理由,Unicode的码表就是这么编的)。然后,l过到UTF的{换,又变?#8220;41”了!q也是可以使用普通文本编辑器查看由JSP生成的JAVA文g的原因;
3、引擎用相当?#8220;javac –encoding UNICODE”的命令,把JAVA文g~译成CLASS文gQ?/p>
先看一下这些过E中中文字符的{换情c有如下源代码:
Q?@ page contentType="text/html; charset=gb2312"%Q<htmlQ<bodyQ<% String a="中文"; out.println(a);%Q</bodyQ</htmlQ?/td> |
q段代码是在UltraEdit for Windows上编写的。保存后Q?#8220;中文”两个字的16q制~码?#8220;D6 D0 CE C4”QGB2312~码Q。经查表Q?#8220;中文”两字的Unicode~码?#8220;\u4E2D\u6587”Q用 UTF表示是“E4 B8 AD E6 96 87”。打开引擎生成的由JSP文g转变而成的JAVA文gQ发现其中的“中文”两个字确实被“E4 B8 AD E6 96 87”替代了,再查看由JAVA文g~译生成的CLASS文gQ发现结果与JAVA文g中的完全一栗?/p>
再看JSP中指定的CharSet为ISO-8859-1的情c?/p>
Q?@ page contentType="text/html; charset=ISO-8859-1"%Q?br>QhtmlQ?br>QbodyQ?br>Q? String a="中文"; out.println(a);%Q?br>Q?bodyQ?br>Q?htmlQ?/td> |
同样Q该文g是用UltraEdit~写的,“中文”q两个字也是存ؓGB2312~码“D6 D0 CE C4”。先模拟一下生成的JAVA文g和CLASS文g的过E:jspc用ISO-8859-1来解?#8220;中文”Qƈ把它映射到Unicode。由于ISO-8859-1?位的Q且是拉丁语p,其映规则就是在每个字节前加“00”Q所以,映射后的Unicode~码应ؓ“\u00D6\u00D0\u00CE\u00C4”Q{化成UTF后应该是“C3 96 C3 90 C3 8E C3 84”。好Q打开文g看一下,JAVA文g和CLASS文g中,“中文”果然都表CZؓ“C3 96 C3 90 C3 8E C3 84”?/p>
如果上述代码中不指定QJsp-charsetQ,xW一行写?#8220;Q?@ page contentType="text/html" %Q?#8221;QJSPC会用file.encoding的设|来解释JSP文g。在RedHat 6.2上,其处理结果与指定为ISO-8859-1是完全相同的?/p>
到现在ؓ止,已经解释了从JSP文g到CLASS文g的{变过E中中文字符的映过E。一句话Q从“JspCharSet到Unicode再到UTF”。下表ȝ了这个过E:
? “中文”从JSP到CLASS的{化过E?/font>
Jsp-CharSet | JSP文g?/td> | JAVA文g?/td> | CLASS文g?/td> |
GB2312 | D6 D0 CE C4(GB2312) | 从\u4E2D\u6587(Unicode)到E4 B8 AD E6 96 87 (UTF) | E4 B8 AD E6 96 87 (UTF) |
ISO-8859-1 | D6 D0 CE C4(GB2312) | 从\u00D6\u00D0\u00CE\u00C4 (Unicode)到C3 96 C3 90 C3 8E C3 84 (UTF) | C3 96 C3 90 C3 8E C3 84 (UTF) |
无(默认Qfile.encodingQ?/td> | 同ISO-8859-1 | 同ISO-8859-1 | 同ISO-8859-1 |
下节先讨论Servlet从JAVA文g到CLASS文g的{化过E,然后再解释从CLASS文g如何输出到客L。之所以这样安排,是因为JSP和Servlet在输出时处理Ҏ是一L?/p>
ServletQ从源文件到Class的过E?/strong>
Servlet源文件是?#8220;.java”l尾的文本文件。本节将讨论Servlet的编译过Eƈ跟踪其中的中文变化?/p>
?#8220;javac”~译Servlet源文件。javac可以?#8220;-encoding QCompile-charsetQ?#8221;参数Q意思是“用< Compile-charset Q中指定的编码来解释Serlvet源文?#8221;?/p>
源文件在~译Ӟ用<Compile-charsetQ来解释所有字W,包括中文字符和ASCII字符。然后把字符帔R转变成Unicode字符Q最后,把Unicode转变成UTF?/p>
在Servlet中,q有一个地方设|输出流的CharSet。通常在输出结果前Q调用HttpServletResponse的setContentTypeҎ来达C在JSP中设|<Jsp-charsetQ一L效果Q称之ؓQServlet-charsetQ?/p>
注意Q文中一共提C三个变量Q<Jsp-charsetQ、<Compile-charsetQ和QServlet-charsetQ。其中,JSP文g只与QJsp-charsetQ有养I而<Compile-charsetQ和QServlet-charsetQ只与Servlet有关?/p>
看下例:
import javax.servlet.*;
import javax.servlet.http.*;
class testServlet extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse resp)
throws ServletException,java.io.IOException
{
resp.setContentType("text/html; charset=GB2312");
java.io.PrintWriter out=resp.getWriter();
out.println("QhtmlQ?);
out.println("#中文#");
out.println("Q?htmlQ?);
}
}
该文件也是用UltraEdit for Windows~写的,其中?#8220;中文”两个字保存ؓ“D6 D0 CE C4”QGB2312~码Q?/p>
开始编译。下表是QCompile-charsetQ不同时QCLASS文g?#8220;中文”两字的十六进制码。在~译q程中,QServlet-charsetQ不起Q何作用。<Servlet-charsetQ只对CLASS文g的输Z生媄响,实际上是QServlet-charsetQ和QCompile-charsetQ一P辑ֈ与JSP文g中的QJsp-charsetQ相同的效果Q因为<Jsp-charsetQ对~译和CLASS文g的输出都会生媄响?/p>
? “中文”从Servlet源文件到Class的{变过E?/font>
Compile-charset | Servlet源文件中 | Class文g?/td> | {效的Unicode?/td> |
GB2312 | D6 D0 CE C4 (GB2312) | E4 B8 AD E6 96 87 (UTF) | \u4E2D\u6587 (在Unicode中=“中文”) |
ISO-8859-1 | D6 D0 CE C4 (GB2312) | C3 96 C3 90 C3 8E C3 84 (UTF) | \u00D6 \u00D0 \u00CE \u00C4 (在D6 D0 CE C4前面各加了一?0) |
无(默认Q?/td> | D6 D0 CE C4 (GB2312) | 同ISO-8859-1 | 同ISO-8859-1 |
普通JavaE序的编译过E与Servlet完全一栗?/p>
CLASS文g中的中文表示法是不是昭然若揭了?OKQ接下来看看CLASS又是怎样输出中文的呢Q?/p>
ClassQ输出字W串
上文说过Q字W串在内存中表现为Unicode~码。至于这UUnicode~码表示了什么,那要看它是从哪种字符集映过来的Q也是说要看它的祖先。这好比在托q行李时Q外观都是纸子Q里面装了什么就要看寄邮件的人实际邮了什么东ѝ?/p>
看看上面的例子,如果l一串Unicode~码“00D6 00D0 00CE 00C4”Q如果不作{换,直接用Unicode码表来对照它Ӟ是四个字W(而且是特D字W)Q假如把它与“ISO8859-1”q行映射Q则直接L前面?#8220;00”卛_得到“D6 D0 CE C4”Q这是ASCII码表中的四个字符Q而假如把它当作GB2312来进行映,得到的结果很可能是一大堆qQ因为在GB2312中有可能没有Q也有可能有Q字W与00D6{字W对应(如果对应不上Q将得到0x3fQ也是问号Q如果对应上了,׃00D6{字W太靠前Q估计也是一些特D符P真正的汉字在Unicode中的~码?E00开始)?/p>
各位看到了,同样的Unicode字符Q可以解释成不同的样子。当Ӟq其中有一U是我们期望的结果。以上例而论Q?#8220;D6 D0 CE C4”应该是我们所惌的,当把“D6 D0 CE C4”输出到IE中时Q用“体中?#8221;方式查看Q就能看到清楚的“中文”两个字了。(当然了,如果你一定要?#8220;西欧字符”来看Q那也没办法Q你得不到M有何时何地的东西Qؓ什么呢Q因?#8220;00D6 00D0 00CE 00C4”本来是由ISO8859-1转化q去的?/p>
l出如下l论Q?/p>
在Class输出字符串前Q会Unicode的字W串按照某一U内码重新生成字节流Q然后把字节输入,相当于进行了一?#8220;String.getBytes(???)”操作???代表某一U字W集?/p>
如果是ServletQ那么,q种内码是在HttpServletResponse.setContentType()Ҏ中指定的内码Q也是上文定义的<Servlet-charsetQ?/p>
如果是JSPQ那么,q种内码是在<%@ page contentType=""%Q中指定的内码,也就是上文定义的QJsp-charsetQ?/p>
如果是JavaE序Q那么,q种内码是file.encoding中指定的内码Q默认ؓISO8859-1?/p>
当输出对象是览器时
以流行的览器IEZ。IE支持多种内码。假如IE接收C一个字节流“D6 D0 CE C4”Q你可以试用各U内码去查看。你会发现用“体中?#8221;时能得到正确的结果。因?#8220;D6 D0 CE C4”本来是体中文中“中文”两个字的~码?/p>
OKQ完整地看一遍?/p>
JSPQ源文g为GB2312格式的文本文Ӟ且JSP源文件中?#8220;中文”q两个汉?/p>
如果指定了<Jsp-charsetQؓGB2312Q{化过E如下表?/p>
? Jsp-charset = GB2312时的变化q程
序号 | 步骤说明 | l果 |
1 | ~写JSP源文Ӟ且存为GB2312格式 | D6 D0 CE C4QD6D0=?CEC4=文) |
2 | jspc把JSP源文件{化ؓ临时JAVA文gQƈ把字W串按照GB2312映射到UnicodeQƈ用UTF格式写入JAVA文g?/td> | E4 B8 AD E6 96 87 |
3 | 把时JAVA文g~译成CLASS文g | E4 B8 AD E6 96 87 |
4 | q行Ӟ先从CLASS文g中用readUTFd字符Ԍ在内存中的是Unicode~码 | 4E 2D 65 87Q在Unicode?E2D=?6587=文) |
5 | ҎJsp-charset=GB2312把Unicode转化为字节流 | D6 D0 CE C4 |
6 | 把字节流输出到IE中,q设|IE的编码ؓGB2312Q作者按Q这个信息隐藏在HTTP头中Q?/td> | D6 D0 CE C4 |
7 | IE?#8220;体中?#8221;查看l果 | “中文”Q正显C) |
如果指定了<Jsp-charsetQؓISO8859-1Q{化过E如下表?/p>
? Jsp-charset = ISO8859-1时的变化q程
序号 | 步骤说明 | l果 |
1 | ~写JSP源文Ӟ且存为GB2312格式 | D6 D0 CE C4QD6D0=?CEC4=文) |
2 | jspc把JSP源文件{化ؓ临时JAVA文gQƈ把字W串按照ISO8859-1映射到UnicodeQƈ用UTF格式写入JAVA文g?/td> | C3 96 C3 90 C3 8E C3 84 |
3 | 把时JAVA文g~译成CLASS文g | C3 96 C3 90 C3 8E C3 84 |
4 | q行Ӟ先从CLASS文g中用readUTFd字符Ԍ在内存中的是Unicode~码 | 00 D6 00 D0 00 CE 00 C4Q啥都不是!Q!Q?/td> |
5 | ҎJsp-charset=ISO8859-1把Unicode转化为字节流 | D6 D0 CE C4 |
6 | 把字节流输出到IE中,q设|IE的编码ؓISO8859-1Q作者按Q这个信息隐藏在HTTP头中Q?/td> | D6 D0 CE C4 |
7 | IE?#8220;西欧字符”查看l果 | qQ其实是四个ASCII字符Q但׃大于128Q所以显C出来的怪模怪样 |
8 | 改变IE的页面编码ؓ“体中?#8221; | “中文”Q正显C) |
奇怪了Qؓ什么把QJsp-charsetQ设成GB2312和ISO8859-1是一个样的,都能正确昄Q因4?中的W?步和W?步互逆,是相?#8220;抉|”的。只不过当指定ؓISO8859-1Ӟ要增加第8步操作,Dؓ不便?/p>
再看看不指定QJsp-charsetQ?时的情况?/p>
? 未指定Jsp-charset 时的变化q程
序号 | 步骤说明 | l果 |
1 | ~写JSP源文Ӟ且存为GB2312格式 | D6 D0 CE C4QD6D0=?CEC4=文) |
2 | jspc把JSP源文件{化ؓ临时JAVA文gQƈ把字W串按照ISO8859-1映射到UnicodeQƈ用UTF格式写入JAVA文g?/td> | C3 96 C3 90 C3 8E C3 84 |
3 | 把时JAVA文g~译成CLASS文g | C3 96 C3 90 C3 8E C3 84 |
4 | q行Ӟ先从CLASS文g中用readUTFd字符Ԍ在内存中的是Unicode~码 | 00 D6 00 D0 00 CE 00 C4 |
5 | ҎJsp-charset=ISO8859-1把Unicode转化为字节流 | D6 D0 CE C4 |
6 | 把字节流输出到IE?/td> | D6 D0 CE C4 |
7 | IE用发求时的页面的~码查看l果 | 视情况而定。如果是体中文,则能正确昄Q否则,需执行?中的W??/td> |
ServletQ源文g为JAVA文gQ格式是GB2312Q源文g中含?#8220;中文”q两个汉?/p>
如果QCompile-charsetQ=GB2312Q<Servlet-charsetQ?GB2312
? Compile-charset=Servlet-charset=GB2312 时的变化q程
序号 | 步骤说明 | l果 |
1 | ~写Servlet源文Ӟ且存为GB2312格式 | D6 D0 CE C4QD6D0=?CEC4=文) |
2 | 用javac –encoding GB2312把JAVA源文件编译成CLASS文g | E4 B8 AD E6 96 87 QUTFQ?/td> |
3 | q行Ӟ先从CLASS文g中用readUTFd字符Ԍ在内存中的是Unicode~码 | 4E 2D 65 87 (Unicode) |
4 | ҎServlet-charset=GB2312把Unicode转化为字节流 | D6 D0 CE C4 (GB2312) |
5 | 把字节流输出到IE中ƈ讄IE的编码属性ؓServlet-charset=GB2312 | D6 D0 CE C4 (GB2312) |
6 | IE?#8220;体中?#8221;查看l果 | “中文”Q正显C) |
如果QCompile-charsetQ=ISO8859-1Q<Servlet-charsetQ?ISO8859-1
? Compile-charset=Servlet-charset=ISO8859-1时的变化q程
序号 | 步骤说明 | l果 |
1 | ~写Servlet源文Ӟ且存为GB2312格式 | D6 D0 CE C4QD6D0=?CEC4=文) |
2 | 用javac –encoding ISO8859-1把JAVA源文件编译成CLASS文g | C3 96 C3 90 C3 8E C3 84 QUTFQ?/td> |
3 | q行Ӟ先从CLASS文g中用readUTFd字符Ԍ在内存中的是Unicode~码 | 00 D6 00 D0 00 CE 00 C4 |
4 | ҎServlet-charset=ISO8859-1把Unicode转化为字节流 | D6 D0 CE C4 |
5 | 把字节流输出到IE中ƈ讄IE的编码属性ؓServlet-charset=ISO8859-1 | D6 D0 CE C4 (GB2312) |
6 | IE?#8220;西欧字符”查看l果 | qQ原因同?Q?/td> |
7 | 改变IE的页面编码ؓ“体中?#8221; | “中文”Q正显C) |
如果不指定Compile-charset或Servlet-charsetQ其默认值均为ISO8859-1?/p>
当Compile-charset=Servlet-charsetӞW?步和W?步能互逆,“抉|”Q显C结果均能正。读者可试着写一下Compile-charsetQ>Servlet-charset时的情况Q肯定是不正的?/p>
当输出对象是数据库时
输出到数据库Ӟ原理与输出到览器也是一L。本节只是ServletZQJSP的情况请读者自行推对{?/p>
假设有一个ServletQ它能接收来自客LQIEQ简体中文)的汉字字W串Q然后把它写入到内码为ISO8859-1的数据库中,然后再从数据库中取出q个字符Ԍ昄到客L?/p>
? 输出对象是数据库时的变化q程Q?Q?/font>
序号 | 步骤说明 | l果 | ?/td> |
1 | 在IE中输?#8220;中文” | D6 D0 CE C4 | IE |
2 | IE把字W串转变成UTFQƈ送入传输中 | E4 B8 AD E6 96 87 | |
3 | Servlet接收到输入流Q用readUTFd | 4E 2D 65 87(unicode) | Servlet |
4 | ~程者在Servlet中必L字符串根据GB2312q原为字节流 | D6 D0 CE C4 | |
5 | ~程者根据数据库内码ISO8859-1生成新的字符?/td> | 00 D6 00 D0 00 CE 00 C4 | |
6 | 把新生成的字W串提交lJDBC | 00 D6 00 D0 00 CE 00 C4 | |
7 | JDBC到数据库内码ؓISO8859-1 | 00 D6 00 D0 00 CE 00 C4 | JDBC |
8 | JDBC把接收到的字W串按照ISO8859-1生成字节?/td> | D6 D0 CE C4 | |
9 | JDBC把字节流写入数据库中 | D6 D0 CE C4 | |
10 | 完成数据存储工作 | D6 D0 CE C4 数据?/td> | |
以下是从数据库中取出数的q程 | |||
11 | JDBC从数据库中取出字节流 | D6 D0 CE C4 | JDBC |
12 | JDBC按照数据库的字符集ISO8859-1生成字符Ԍq提交给Servlet | 00 D6 00 D0 00 CE 00 C4 (Unicode) | |
13 | Servlet获得字符?/td> | 00 D6 00 D0 00 CE 00 C4 (Unicode) | Servlet |
14 | ~程者必L据数据库的内码ISO8859-1q原成原始字节流 | D6 D0 CE C4 | |
15 | ~程者必L据客L字符集GB2312生成新的字符?/td> | 4E 2D 65 87QUnicodeQ?/td> | |
Servlet准备把字W串输出到客L | |||
16 | ServletҎQServlet-charsetQ生成字节流 | D6D0 CE C4 | Servlet |
17 | Servlet把字节流输出到IE中,如果已指定<Servlet-charsetQ,q会讄IE的编码ؓQServlet-charsetQ?/td> | D6 D0 CE C4 | |
18 | IEҎ指定的编码或默认~码查看l果 | “中文”Q正显C) | IE |
解释一下,表中W?W?步和W?5W?6步是用红色标记的Q表Cq码者来作{换。第4?两步其实是一句话Q?#8220;new String(source.getBytes("GB2312"), "ISO8859-1")”。第15?6两步也是一句话Q?#8220;new String(source.getBytes("ISO8859-1"), "GB2312")”。亲q读者,你在q样~写代码时是否意识到了其中的每一个细节呢Q?/p>
至于客户端内码和数据库内码ؓ其它值时的流E,和输出对象是pȝ控制台时的流E,误者自己想吧。明白了上述程的原理,怿你可以轻村֜写出来?/p>
行文xQ已可告一D落了。终点又回到了v点,对于~程者而言Q几乎是什么媄响都没有?/p>
因ؓ我们早就被告之要q么做了?/p>
以下l出一个结论,作ؓl尾?/p>
1?在Jsp文g中,要指定contentTypeQ其中,charset的D与客L览器所用的字符集一P对于其中的字W串帔RQ不需做Q何内码{换;对于字符串变量,要求能根据ContentType中指定的字符集还原成客户端能识别的字节流Q简单地_是“字符串变量是ZQJsp-charsetQ字W集?#8221;Q?/p>
2?在Servlet中,必须用HttpServletResponse.setContentType()讄charsetQ且讄成与客户端内码一_对于其中的字W串帔RQ需要在Javac~译时指定encodingQ这个encoding必须与编写源文g的^台的字符集一P一般说来都是GB2312或GBKQ对于字W串变量Q与JSP一P必须“是基于<Servlet-charsetQ字W集?#8221;?/p>
struts+newxy之所以在开发效率上比struts+hibernate能提高十倍、甚臛_十倍,是因为克服了struts与hiberate的不?利用newxy DAOc,标签Q?struts+newxy可以在以下几个方面不用写java代码Q不用配|struts?1.数据库的增、删、改Q?2.Ҏ询所得数据缓存,指定~存旉Q?3.数据库字W编码与本地字符~码转换Q?4.文g上传Q上传大控Ӟ 5.文g下蝲Q下载记敎ͼ 6.囄昄Q?7.数据分页昄Q?8.客户端标记记录集哪条记录被选择Q?因ؓ可以不写java代码Q不用徏立ActionFormcRActionc,因而不用配|strutsQ不用重新编译类文g、不用重新打包、不用重启服务器?可以克服struts的不?׃struts+newxy用即时注册的ҎQ可以不?/p>
在java的web开发领域较ȝ的是数据库操U,如果有工兯像delphi开发数据库q用pȝ那样高效Q它一定会受到开发者的Ƣ迎?
l过五个斚w的比较,newxy+struts WEB开发与deiphi桌面开发相比,速度更快Q能力更强?http://blog.csdn.net/nlhlx/archive/2006/06/12/791047.aspx
newxy是hibernate的替代者,struts+newxy是struts+hibernate的替代方案?
struts的不I下面一文章有代表性:《Struts的巨大烦?真的不适合大系l??a >http://dev.csdn.net/develop/article/85/85114.shtm?br />主要观点是:
一、{到展C层Ӟ需要配|forwardQ每一ơ{到展C层Q相信大多数都是直接转到jspQ?而涉及到转向Q需要配|forwardQ如果有十个展示层的jspQ需要配|十ơstrutsQ?而且q不包括有时候目录、文件变_需要重C改forwardQ注意,每次修改配置之后Q?要求重新部v整个目Q而tomcateq样的服务器Q还必须重新启动服务器,如果业务变更复杂频繁的系l, q样的操作简单不可想象。现在就是这P几十上百个h同时在线使用我们?pȝQ?大家可以惌一下,我的烦恼有多大?br /> 二、当面表单需要自动变化或者频J变化时?br /> 对于一个成熟的MISpȝ来说,面表单肯定是不固定?甚至象有些系l,面表单是存在数据库中, 需要填写的表单在页面自动生成,比如填写一个h员基本信?本来只需要填?姓名、性别、出生年?三个指标Q?而我后来需要增加籍贯这L指标Q我只需要在数据库中dc诏q个记录Qƈ在页面就能自动增加籍贯这L表单??struts在这斚wQ其优势反而变成了不Q我参考了非常多的人力资源理pȝQ这些系l几乎都能够做系l里面就可以控制人员信息的指C, q行使展C层能随之灵zd化,如果使用了strutsQ这些灵zL就Ҏ用不上。 同时Q如果页面表单频J变化时Q就需要频J修改formbean对应的方法和属性,而每ơ修改之后,p求重新部|Ԍ或者重新启动服务器……?br /> hibernate的不I下面是一位网友的看法Q具有代表性:
一、对象与数据库的映射Q关键在于对象关pȝ映射Q但是没做到很理惻I配置q多Q控制复杂, 另外q会出错。其实本质在于对象不够自由?br /> 二、事务处理。这点上更容易出问题Q相对于各种各样的事务管理器Q要兼容是一个大问题Q?d在各U应用服务器上有很多问题。其本质在于创徏了一个自我数据存取小环境Q必焉临各U兼定w题?br /> 三、HQL语言。徏立对象查询语aQ类SQLQ但是不同于M一USQLQ调试环境复杂。本质在于创Z一U语aQ增加学习成本?br /> q位|友q提Z减化和退化方案?
struts+newxy之所以在开发效率上比struts+hibernate能提高十倍、甚臛_十倍,是因为克服了struts与hiberate的不?br /> 利用newxy DAOc,标签Q?struts+newxy可以在以下几个方面不用写java代码Q不用配|struts?http://blog.csdn.net/nlhlx/archive/2006/06/11/788541.aspx
1.数据库的增、删、改Q?
2.Ҏ询所得数据缓存,指定~存旉Q?
3.数据库字W编码与本地字符~码转换Q?
4.文g上传Q上传大控Ӟ
5.文g下蝲Q下载记敎ͼ
6.囄昄Q?
7.数据分页昄Q?
8.客户端标记记录集哪条记录被选择Q?
因ؓ可以不写java代码Q不用徏立ActionFormcRActionc,因而不用配|strutsQ不用重新编译类文g、不用重新打包、不用重启服务器?可以克服struts的不?br /> 在克服hibernate的不x面,newxy采用“退化”和“进化”ƈ用的Ҏ?br /> newxy在进行数据的查询、增、删、改旉会调用一注册ҎQ根据业务涉及到的数据库相关数据源名和表名进行注册, 注册的目的是要获得表字段对应的javacdQ主关键字段名,d键字D长度等数据Q保存在一个单子实例中Q以供DAOc调用?如果已注册不再注册?br /> 可以对多表查询语句注册,如:“select a.field1,b.field2 from table1 as a,table2 as b where ...";
可以对跨数据源的查询注册。如Q?select a.field1,b.field2 from table1 as a,DB3.dto.table2 as b where ...";
如果是数据增、删、改Q则是对单一表注册;
׃struts+newxy用即时注册的ҎQ可以不象hibernate那样用静态文件媄数据库到值对象类。开发者不用配|Q何文件。可以用Q意查询语句,克服“对象不够自由”问题?br /> hibernate通过配置文g讄表之间的关系Q有一定意义,newxy在这斚w是“退化”的Q但struts+newxy在处理数据库表之间关pL面是很容易的?br /> 在事务处理方面,newxy提供了一事务cnet.newxy.dbm.Transaction。它可以多个数据库的操作放在一个事务中。由于DAOcd数据操作前的注册Ҏ得到的表及其字段各种Ҏ都是与数据库直接相关的Q而不是事先用静态文件媄, 因而极发生错误;开发者可以通过Transaction的方法ؓ不同的数据库讄不同的隔ȝU;可以讄操时回滚旉Q在讄的时间内事务没有完成Q会有一U程q行q预Q将事务回滚?br /> hibernate的HQL语言是和数据库与对象影射规则盔R应的,它没有特别功能,主要是利用值对象类来查询数据?newxy也提供了一U查询语aNQL。开发者不需用特D的语法来构建查询语句。非常容易理解,不会增加学习成本?
struts一旦与newxyl合C赯用是如此单,下列是struts+newxy代替struts+hibernate的例子?
struts配置中,formBean的type是“net.newxy.struts_faces.DynaFormBean”,开发者不需另外设计ActionFormcR如Q?br /> <form-bean name="myFormBean" type="net.newxy.struts_faces.DynaFormBean" />
用户从页面表单submit数据后,在ActioncȝҎ中,开发者可以用DynaFormBean代替struts ActionForm,用DynaDto代替hibernate 对象cR?br /> public ActionForward methodName(ActionMapping actionMapping, ActionForm actionForm,
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws Exception{
......
DynaFormBean form=(DynaFormBean)actionForm;
DynaDto dto=(DynaDto)form.getDto();
dto.set_table("table1");//如果用户面没有传来数据库表名?br /> try{
IFacade ifacade=IFacadeFactory.getFacade(httpServletRequest.getParameter("_dao"),
httpServletRequest.getLocale()); //l大多数情况是:IFacade ifacade=IFacadeFactory.getFacade();
//更新或插入,如果result==null,为updateQ否则ؓinsert?br /> result = ifacade.update(dto);//或:FormBeanUtils.update(ifacade, form);
//删除记录
ifacade.remove(dto);//?FormBeanUtils.remove(ifacade, form);
//数据查询Q如果上传了W合newxy多项查询规则的数据。查询记录集攑֜newForm 的_coll属性中?br /> DynaFormBean newForm=new DynaFormBean();
FormBeanUtils.createForm(newForm, httpServletRequest);
......
//开发者如果想知道生成的sql语句Q可以这P
//string sql=form.get_sql();
//׃开发者在Ҏ据进行操作时完全不需知道sql语句Q所以没有提供方法让开发者直接得到sql语句来控制数据操作?br /> //未来版本可能提供q样的方法?br /> }catch(Exception e){
......
}
}
如果使用newxy的标{֏以不建立Actionc,不设|struts的formBean及actionQ可以不写代码?br />
public Long getId()
{
return id;
}
public void setId( Long id )
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName( String name )
{
this.name = name;
}
public String getPassword()
{
return password;
}
public void setPassword( String password )
{
this.password = password;
}
public String getTelphone()
{
return telphone;
}
public void setTelphone( String telphone )
{
this.telphone = telphone;
}
public String getUser()
{
return user;
}
public void setUser( String user )
{
this.user = user;
}
}
package com.boya.subject.model;
public class Admin extends User
{
private String grade = null;
理员权?/font>
public String getGrade()
{
return grade;
}
public void setGrade( String grade )
{
this.grade = grade;
}
public String getType()
{
return "admin";
}
}
package com.boya.subject.model;
public class Teacher extends User
{
private String level;
教师职称
public String getLevel()
{
return level;
}
public void setLevel( String level )
{
this.level = level;
}
public String getType()
{
return "teacher";
}
}
package com.boya.subject.model;
public class Student extends User
{
private String sn;学生学号
private SchoolClass schoolClass;
班
public SchoolClass getSchoolClass()
{
return schoolClass;
}
public void setSchoolClass( SchoolClass schoolClass )
{
this.schoolClass = schoolClass;
}
public String getSn()
{
return sn;
}
public void setSn( String sn )
{
this.sn = sn;
}
public String getType()
{
return "student";
}
}
而对于Action我分别做了一个抽象类Q之后别的从q里l承
先是Action?/font>
package com.boya.subject.controller;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import com.boya.subject.frame.ID;
import com.boya.subject.frame.ServiceFactory;
import com.boya.subject.model.Person;
import com.boya.subject.service.Service;
import com.boya.subject.util.HtmlUtil;
public abstract class BaseAction extends Action
{
/**
* 由服务工厂方法创建服?br /> * @return 数据库操作的服务
* 2006-5-16 18:10:04
*/
public Service getService()
{
ServiceFactory factory = (ServiceFactory) getAppObject( ID.SF );
Service service = null;
try
{
service = factory.createService();
}
catch ( Exception e )
{
}
return service;
}
/**
* 判断用户是否合法登陆
* @param req
* @return 用户是否登陆
* 2006-5-16 18:11:26
*/
public boolean isLogin( HttpServletRequest req )
{
if ( getPerson( req ) != null ) return true;
else
return false;
}
/**
* 抽象Ҏ,子类实现
* @param mapping
* @param form
* @param req
* @param res
* @return
* @throws Exception
* 2006-5-16 18:12:54
*/
protected abstract ActionForward executeAction( ActionMapping mapping,
ActionForm form, HttpServletRequest req, HttpServletResponse res )
throws Exception;
/**
* 获取session范围的用?br /> * @param req
* @return 当前用户
* 2006-5-16 18:13:35
*/
public abstract Person getPerson( HttpServletRequest req );
/**
* 父类的执行Action
* @see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
public ActionForward execute( ActionMapping mapping, ActionForm form,
HttpServletRequest req, HttpServletResponse res ) throws Exception
{
if ( !isLogin( req ) )
{
HtmlUtil.callParentGo( res.getWriter(), ID.M_UNLOGIN, ID.P_INDEX );
return null;
}
return executeAction( mapping, form, req, res );
}
/**
* 删除session中属性ؓattribute的对?br /> * @param req
* @param attribute 对象属?br /> * 2006-5-16 18:16:59
*/
public void removeSessionObject( HttpServletRequest req, String attribute )
{
HttpSession session = req.getSession();
session.removeAttribute( attribute );
}
/**
* 讄session中属性ؓattribute的对?br /> * @param req
* @param attribute 讄属?br /> * @param o 讄对象
* 2006-5-16 18:17:50
*/
public void setSessionObject( HttpServletRequest req, String attribute,
Object o )
{
req.getSession().setAttribute( attribute, o );
}
/**
* 讄application中属性ؓattribute的对?br /> * @param req
* @param attribute 讄属?br /> * @param o 讄对象
* 2006-5-16 18:17:50
*/
public void setAppObject( String attribute, Object o )
{
servlet.getServletContext().setAttribute( attribute, o );
}
public Object getSessionObject( HttpServletRequest req, String attribute )
{
Object obj = null;
HttpSession session = req.getSession( false );
if ( session != null ) obj = session.getAttribute( attribute );
return obj;
}
public Object getAppObject( String attribute )
{
return servlet.getServletContext().getAttribute( attribute );
}
public void callParentGo( HttpServletResponse res, String msg, String url )
throws IOException
{
HtmlUtil.callParentGo( res.getWriter(), msg, url );
}
public void callMeGo( HttpServletResponse res, String msg, String url )
throws IOException
{
HtmlUtil.callMeGo( res.getWriter(), msg, url );
}
public void callBack( HttpServletResponse res, String msg )
throws IOException
{
HtmlUtil.callBack( res.getWriter(), msg );
}
public void callMeConfirm( HttpServletResponse res, String msg, String ok,
String no ) throws IOException
{
HtmlUtil.callMeConfirm( res.getWriter(), msg, ok, no );
}
}
再是DispatchAction?br />
package com.boya.subject.controller;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;
import com.boya.subject.frame.ID;
import com.boya.subject.frame.ServiceFactory;
import com.boya.subject.model.Person;
import com.boya.subject.service.Service;
import com.boya.subject.util.HtmlUtil;
public abstract class BaseDispatchAction extends DispatchAction
{
/**
* 由服务工厂方法创建服?br /> * @return 数据库操作的服务
* 2006-5-16 18:10:04
*/
public Service getService()
{
ServiceFactory factory = (ServiceFactory) getAppObject( ID.SF );
Service service = null;
try
{
service = factory.createService();
}
catch ( Exception e )
{
}
return service;
}
/**
* 判断用户是否合法登陆
* @param req
* @return 用户是否登陆
* 2006-5-16 18:11:26
*/
public boolean isLogin( HttpServletRequest req )
{
if ( getPerson( req ) != null ) return true;
else
return false;
}
/**
* 获取session范围的用?br /> * @param req
* @return 当前用户
* 2006-5-16 18:13:35
*/
public abstract Person getPerson( HttpServletRequest req );
/**
* 父类的执行DispatchAction
* @see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
public ActionForward execute( ActionMapping mapping, ActionForm form,
HttpServletRequest req, HttpServletResponse res ) throws Exception
{
try
{
if ( !isLogin( req ) )
{
callParentGo( res, ID.M_UNLOGIN, ID.P_INDEX );
return null;
}
return super.execute( mapping, form, req, res );
}
catch ( NoSuchMethodException e )
{
callBack( res, ID.M_NOMETHOD );
return null;
}
}
/**
* 删除session中属性ؓattribute的对?br /> * @param req
* @param attribute 对象属?br /> * 2006-5-16 18:16:59
*/
public void removeSessionObject( HttpServletRequest req, String attribute )
{
HttpSession session = req.getSession();
session.removeAttribute( attribute );
}
/**
* 讄session中属性ؓattribute的对?br /> * @param req
* @param attribute 讄属?br /> * @param o 讄对象
* 2006-5-16 18:17:50
*/
public void setSessionObject( HttpServletRequest req, String attribute,
Object o )
{
req.getSession().setAttribute( attribute, o );
}
/**
* 讄application中属性ؓattribute的对?br /> * @param req
* @param attribute 讄属?br /> * @param o 讄对象
* 2006-5-16 18:17:50
*/
public void setAppObject( String attribute, Object o )
{
servlet.getServletContext().setAttribute( attribute, o );
}
public Object getSessionObject( HttpServletRequest req, String attribute )
{
Object obj = null;
HttpSession session = req.getSession( false );
if ( session != null ) obj = session.getAttribute( attribute );
return obj;
}
public Object getAppObject( String attribute )
{
return servlet.getServletContext().getAttribute( attribute );
}
public void callParentGo( HttpServletResponse res, String msg, String url )
throws IOException
{
HtmlUtil.callParentGo( res.getWriter(), msg, url );
}
public void callMeGo( HttpServletResponse res, String msg, String url )
throws IOException
{
HtmlUtil.callMeGo( res.getWriter(), msg, url );
}
public void callBack( HttpServletResponse res, String msg )
throws IOException
{
HtmlUtil.callBack( res.getWriter(), msg );
}
public void callMeConfirm( HttpServletResponse res, String msg, String ok,
String no ) throws IOException
{
HtmlUtil.callMeConfirm( res.getWriter(), msg, ok, no );
}
}
对于E序中的一些提CZ息,我比较喜Ƣ用JS来写Q所以我把这些都攑ֈ了一个类?br />
import java.io.IOException;
import java.io.Writer;
public class HtmlUtil
{
public static void callParentGo( Writer out, String msg, String url )
throws IOException
{
out.write( "<script language=\"javascript\">" );
out.write( "alert(\"" + msg + "\");" );
out.write( "parent.location.href=\"" + url + "\";" );
out.write( "</script>" );
}
public static void callMeGo( Writer out, String msg, String url )
throws IOException
{
out.write( "<script language=\"javascript\">" );
out.write( "alert(\"" + msg + "\");" );
out.write( "location.href=\"" + url + "\";" );
out.write( "</script>" );
}
public static void callMeConfirm( Writer out, String msg ,String ok, String no )
throws IOException
{
out.write( "<script language=\"javascript\">" );
out.write( "if(window.confirm(\"" + msg + "\")){" );
out.write( "location.href=\"" + ok + "\"}else{" );
out.write( "location.href=\"" + no + "\"}" );
out.write( "</script>" );
}
public static void callBack( Writer out, String msg ) throws IOException
{
out.write( "<script language=\"javascript\">" );
out.write( "alert(\"" + msg + "\");" );
out.write( "parent.history.back();" );
out.write( "</script>" );
}
}