??xml version="1.0" encoding="utf-8" standalone="yes"?> q段旉在研IStruts2Q学习资料是C市的李刚著的《Struts2权威指南》,很不错的一本书Q看了觉得收获很大。刚研究完Struts2中的Ajax输入校验Qƈ做了一些例子,现ȝ如下Q?/p>
? 讄面的Ajax主题 ? 讄校验规则 在用struts2.0标签开发中,l常要用form提交. 通常: 1)写一个actionc?br />
此actioncd成提交后的保存动? 2)写一个静态jsp面 问题: 在点?提交"?我们通常会弹Z个提CZ息的面,用户此时有可能会按f5h当前提交的action,从而将多个相同的数据保存到了后台数据库,q且造成了潜在的安全危险! 1) ?lt;s:token>! <form name="myname" action="myaction.do" method="post"> <input type="text" name="stuName" value="" .../> ... ... <s:token/> <input type="button" onclick="mymethod(this.form);" .../> </form> 2) 在struts****.xml文g里配|拦截器: <!-- 保存 --> 3)写一个名UCؓNoBack.jsp的提C文?当重复f5h?显C本内?提示"不可重复提交,或者页面已l过? <s:token/>在最l生成页面时,自动生成一个unique id,通过它拦截器才能知道面是否是同一ơ提? 最q我们公司的|站在进行优化动作,要想采用一U好点的技术,使得原来的PHP动态Ş式的|页文g能够被GOOGLE{搜索引擎更加容易地收入其中Q目前我们已l采用了一些改q办法:比如在后台用PHPE序原来的文gҎ(gu)HTM内容Q采用Apache的Path_Info技术,但觉得还是不够强大,因此军_采用Apache中的URL Rewrite技术来试用一下?/p>
很早注意到它了Q但一直不知道怎么实现Q今天咬咬牙Q翻了N有关的文章Q终于实C一些基本的功能Q?/p>
1、修改http.conf 在你要修改网站的根目录下Q?/p>
2、先修改http.conf 然后再在此目录下建立一?htacess文gQ它的内容如下: q样实Chttp://localhost/news/1000.html 解析?http://localhost/news.php?id=1000的功?/p>
附录Q?一个网站的.htacess文g) ------------------------------------------------------------------------------- ErrorDocument 401 /error.php #show category #show brands #show products 1) R[=code](force redirect) 强制外部重定?br />
强制在替代字W串加上http://thishost[:thisport]/前缀重定向到外部的URL.如果code不指定,用~省?02 HTTP状态码?br />
2) F(force URL to be forbidden)用URL,q回403HTTP状态码?br />
3) G(force URL to be gone) 强制URL为GONEQ返?10HTTP状态码?br />
4) P(force proxy) 强制使用代理转发?br />
5) L(last rule) 表明当前规则是最后一条规则,停止分析以后规则的重写?br />
6) N(next round) 重新从第一条规则开始运行重写过E?br />
7) C(chained with next rule) 与下一条规则关?br />
如果规则匚w则正常处理,该标志无效,如果不匹配,那么下面所有关联的规则都蟩q?br />
8) T=MIME-type(force MIME type) 强制MIMEcd 关于UrlRewrite静态化的说明: (1)apache用户,首先认(zhn)的服务器是apache架设的web服务器(此插件只使用于apache架设的服务器Q?br />
Apache Web ServerQ独立主机用P The requested URL thread-11955.html was not found on this server 困惑了一天,修改了很多次规则都不行。后来尝试着l合虚拟L用户Ҏ(gu)。首先把httpd.conf中的规则 配置LQ然?/font>在论坛根目录创徏.htaccess 文gQ然后把规则写进去,重启apacheQ一切OK啦?/font> 规则如下Q?/font> <IfModule mod_rewrite.c>
</IfModule>
2、如果用UrlrewriteQ要指定filter-mapping的dispatcher方式Q如? 3、在做上传文件的时候,要在web.xml中增加ActionContextCleanUpq个filterQ如果不增加Q会发生W一ơ上传取不到文g的情? 4、在Apache+Resin的情况下Q要在WEB-INF下增加resin-web.xmlQ该文g只针对Resin有效Q作用是指定后缀?Resin的Servlet引擎匚wQ要不然从Apache转发q去的请求到Resin后会出现404的情况,resin-web.xml举例如下Q? 5、在使用<s:url/>标签的时候,会出现将get或post数值带入url参数的情况,如果不需要这些参敎ͼ可以在struts.properties文g中设|? 6、与webwork基本相同QStruts2提供了几Uui.themeQ有xhtml、css_xhtml、simple{等Q在 struts.properties中可以设|用何UthemeQ这一点很关键Q不同的themeQstruts的tag会生成不同的html代码Q?且在某些情况下这些theme不能满面要求Q则需要自p行扩展了Q这些theme都是由freemarker写的Q仿照这写就可以?/p>
7、单个checkbox的标记库好像只能q回boolean的|如果在数据库中设计ؓint型,则需要做一些{换,q一Ҏ(gu)觉得不如Struts1.x的方ѝ?/p>
8、M来说Struts2的标记库使用上比Struts1.x的方便,面整体也比较简z,Struts2采用stack的方式存取数据,与Struts1相比各有千秋吧?/p>
Struts2主要延箋自webworkQ以前用webwork的朋友{q来q不困难QStruts2的几个核心的部分Q比如拦截器、Result Configuration、OGNL stack{等q是需要仔l的体会Q深入了解,才能做出优秀的系l?/p>
首先使用dojo的工具shrinksafe(http://shrinksafe.dojotoolkit.org/)压羃一?dojo的这个工具会L注释Q他的压~不是简单的替换变量Q而是利用了mozilla的一个工?对js解析后才压羃Q确保压~后的代码不会出错?/p>
dojo压羃后,q不会减太多,下一步可以用http://javascriptcompressor.com/q个站点q行更高层次的压~?可惜只能登陆q个站点再压~,只能你的js代码复制的他的文本框Q然后等他的压羃输出 l过q?步,你的js会变得既安全,文g又小
公司|站Q?a >http://www.bejate.com
]]>
Ajax的输入校验不是客L校验Q而是服务器端校验Q但q种服务器端校验是以异步方式q行的,览者无需昄提交hQ当览者输入完成后Q系l自动完成校验。Struts2的Ajax校验建立在DWR和Dojo两个框架之上Q其中DWR负责实现在JavaScript中调用远EJavaҎ(gu)Q而Dojo则负责实现页面效果的实现?br />
一. 配置DWR的核心Servlet
DWR是Java领域的Ajax框架Q它允许客户端JavaScript代码直接调用服务器端的JavaҎ(gu)Q而这个过E是通过一个核心Servlet的{换来实现的。ؓ了让DWR的核心Servlet起作用,必须在web.xml文g中配|该核心Servlet。配|DWR的核心Servlet的配|片D如下:
<!-- 配置Struts2的核心Servlet -->
<servlet>
<servlet-name>dwr</servlet-name>
<!-- 指定Servlet的实现类 -->
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<!-- 指定处于开发阶D?-->
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<!-- 指定DWR的核心Servlet拦截的URL -->
<servlet-mapping>
<servlet-name>dwr</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
在上面配|文件中增加了DWR的核心Servlet后,该Servlet负责服务器端的JavaҎ(gu)暴露出来。到底那些JavaҎ(gu)需要被暴露出来Q通过在dwr.xml配置文g中指定即可,因此需要在本应用中增加一个dwr.xml文g?br />
提示Q此处ƈ不许需要开发者自己开发Ajax应用Qƈ不需要开发者利用DWR框架Q我们只需利用Struts2对DWR的封装即可。因此,只需在Web应用的WEB-INF路径下增加dwr.xml文g卛_Q而且dwr.xml文g的代码也是固定的Q?br />
<!DOCTYPE dwr PUBLIC
"-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
"
<dwr>
<!-- 定义所有需要被暴露的JavaҎ(gu) -->
<allow>
<!-- 定义org.apache.struts2.validators.DWRValidator创徏成一个validator对象 -->
<create creator="new" javascript="validator">
<param name="class" value="org.apache.struts2.validators.DWRValidator"/>
</create>
<!-- 定义一个{换器 -->
<convert converter="bean" match="com.opensymphony.xwork2.ValidationAwareSupport"/>
</allow>
<signatures>
<![CDATA[
import java.util.Map;
import org.apache.struts2.validators.DWRValidator;
DWRValidator.doPost(String, String, Map<String, String>);
]]>
</signatures>
</dwr>
在上面配|文件中Q将org.apache.struts2.validators.DWRValidatorcd建成一个JavaScript对象Q这个对象名为validator。当Ӟq里所说的创徏是假创徏Q因为JavacL无法创徏JavaScript对象Q但DWR提供一U方式,允许当我们在客户端调用validator的方法时Q{换成调用DWRValidator实例的方法?br />
提示Q关于DWR的运行原理和使用l节Q请读者参考笔者所著的《基于J2EE的Ajax宝典》一书。此处由于篇q管理,无法详述DWR的用法和l节?br />
实际上,对于一个Struts2的开发者而言Q无需理会q些实现l节Q因为Struts2已经为我们提供了q些装Q我们只需要在Struts2装的基上进行开发即可?br />
值得指出的是Qؓ了让Web应用增加DWR支持Q显然还需要将DWR的二q制包复制到Web应用中。即使对于Struts2.0.6正式版,依然不支持DWR的的最新版本(DWR的最新版本是2.0.1Q,因此只能使用DWR的前一个正式版1.1.3Q将dwr-1.1.3.jar文g复制到Web应用中即可?br />
提示Q由于Struts2发行版中q未包含DWR二进制文件。因此,dwr-1.1.3.jar文g必须到DWR的官方站点(http://getahead.ltd.uk/dwr/Q自行下载?/p>
正如前面已经提到的,实现Ajax交互必须在页面中导入Ajax风格的controlheader.ftlQ这个控件负责当每个输入lg失去焦点Ӟ输入结果发送到服务器端q行校验?br />
Z实现Ajax校验Q还需要将表单讄成Ajax主题Qƈ且设|validate="true"。下面是本示例应用中regist.jsp面的代码:
<%@ page language="java" contentType="text/html; charset=GBK"%>
<!-- 导入Struts2标签?-->
<%@taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>误入?zhn)的注册信?lt;/title>
<!-- 导入Ajax主题的controlheader.ftl -->
<s:head theme="ajax"/>
</head>
<body>
<H1>误入?zhn)的注册信?lt;/H1>
<!-- 讄表单使用Ajax主题Qƈ且设|validate="true" -->
<s:form action="regist" theme="ajax" validate="true">
<s:textfield name="name" label="作者名"/><br>
<s:textfield name="pass" label="密码"/>
<s:textfield name="age" label="q龄"/>
<s:textfield name="birth" label="生日"/>
<s:submit value="注册"/>
</s:form>
</body>
</html>
在上面的表单被设|成Ajax主题Q这意味着该表单是一个远E表单)Qƈ且设|了validate="true"属性。一旦完成了上面讄后,当某个输入组件失ȝҎ(gu)Q系l会负责输入内容发送到服务器端q行校验?/p>
对于使用Ajax校验的Actionc,与基本校验的Actioncdƈ没有太大的不同之处。但必须指出Q尽量不要重写ActioncȝvalidateҎ(gu)Q重写该Ҏ(gu)来完成Ajax校验可能出现一些未知异常(q可能是Struts2q需要完善的地方Q?br />
注意Q不同通过重写validateҎ(gu)来完成Ajax校验?br />
Z完成输入校验Q我们通过定义自己的校验规则文件来完成输入校验Q本输入校验文g使用字段校验器风格来配置校验规则。下面是校验文g的代码:
文gQ该文g指定了Action的属性必Lx样的规则,下面是该应用中Action的校验文件的代码?br />
<?xml version="1.0" encoding="GBK"?>
<!-- 指定校验配置文g的DTD信息 -->
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"
<!-- 校验文g的根元素 -->
<validators>
<!-- 校验Action的name属?-->
<field name="name">
<!-- 指定name属性必L_填规?-->
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>必须输入名字</message>
</field-validator>
<!-- 指定name属性必d配正则表辑ּ -->
<field-validator type="regex">
<param name="expression"><![CDATA[(\w{4,25})]]></param>
<message>(zhn)输入的用户名只能是字母和数l,且长度必d4?5之间</message>
</field-validator>
</field>
<!-- 校验Action的pass属?-->
<field name="pass">
<!-- 指定pass属性必L_填规?-->
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>必须输入密码</message>
</field-validator>
<!-- 指定pass属性必L_配指定的正则表达?-->
<field-validator type="regex">
<param name="expression"><![CDATA[(\w{4,25})]]></param>
<message>(zhn)输入的密码只能是字母和数组Q且长度必须??5之间</message>
</field-validator>
</field>
<!-- 指定age属性必d指定范围?->
<field name="age">
<field-validator type="int">
<param name="min">1</param>
<param name="max">150</param>
<message>q纪必须??50之间</message>
</field-validator>
</field>
<!-- 指定birth属性必d指定范围?->
<field name="birth">
<field-validator type="date">
<!-- 下面指定日期字符串时Q必M用本Locale的日期格?-->
<param name="min">1900-01-01</param>
<param name="max">2050-02-21</param>
<message>q纪必须?{min}?{max}之间</message>
</field-validator>
</field>
</validators>
实际上,q䆾校验文g与之前进行基本校验的校验文gq没有太大的区别。这也证明了Struts2框架的简单、易用?br />
完成上面定义后,如果览者在输入面中输入用户名Q将焦点Ud密码输入框时Q将看到Ajax校验效果?/p>
]]>
写form,以及输入input,和提交button.
3)讄struts*****.xml文g
配置action名称以及映射的类和返回结果名U等.
如何避免重复提交?
如在输入界面的jsp?讄token标志:
<action name="Save"
class="com.yourcom.app.Action.Dataform.saveAction"
method="Save">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="token" />
<result name="invalid.token">/Info/NoBack.jsp</result>
</action>
]]>
DefaultType application/x-httpd-php
rewriteengine on #必须
options followsymlinks #必须
RewriteRule /news/(\d+)\.html /news\.php\?id=$1 [N,L] #规则
AllowOverride All
DefaultType application/x-httpd-php
options followsymlinks
AllowOverride All
rewriteengine on
rewritebase /websamples/urlrewrite/
RewriteRule news/(\d+)\.html news\.php\?id=$1 [N,L]
rewriteengine on
rewritebase /websamples/urlrewrite/power-for-less.com/
#
RewriteRule ^((laptop([^/]*))|(camcorder([^/]*))|(((digital)?).?camera([^/]*))|(power([^/]*))|(pda([^/]*))|(mobile([^/]*))|(two-way([^/]*))|(scanner([^/]*))|(mp3([^/]*)))\.htm(l?)$ babrand\.php\?fclassname=$1 [NC]
#
RewriteRule ^(laptop([^/]*))/([^/]+)\.htm(l?)$ series\.php\?fclassname=$1&fb_babrand=$3 [NC]
RewriteRule ^(camcorder([^/]*))/([^/]+)\.htm(l?)$ series\.php\?fclassname=$1&fb_babrand=$3 [NC]
RewriteRule ^(((digital)?).?camera([^/]*))/([^/]+)\.htm(l?)$ series\.php\?fclassname=$1&fb_babrand=$5 [NC]
RewriteRule ^(power([^/]*))/([^/]+)\.htm(l?)$ series\.php\?fclassname=$1&fb_babrand=$3 [NC]
RewriteRule ^(pda([^/]*))/([^/]+)\.htm(l?)$ series\.php\?fclassname=$1&fb_babrand=$3 [NC]
RewriteRule ^(mobile([^/]*))/([^/]+)\.htm(l?)$ series\.php\?fclassname=$1&fb_babrand=$3 [NC]
RewriteRule ^(two-way([^/]*))/([^/]+)\.htm(l?)$ series\.php\?fclassname=$1&fb_babrand=$3 [NC]
RewriteRule ^(scanner([^/]*))/([^/]+)\.htm(l?)$ series\.php\?fclassname=$1&fb_babrand=$3 [NC]
RewriteRule ^(mp3([^/]*))/([^/]+)\.htm(l?)$ series\.php\?fclassname=$1&fb_babrand=$3 [NC]
#
RewriteRule ^(laptop([^/]*))/([^/]+)/(.+)\.htm(l?)$ product\.php\?fclassname=$1&fb_babrand=$3&code=$4 [NC]
RewriteRule ^(camcorder([^/]*))/([^/]+)/(.+)\.htm(l?)$ product\.php\?fclassname=$1&fb_babrand=$3&code=$4 [NC]
RewriteRule ^(((digital)?).?camera([^/]*))/([^/]+)/(.+)\.htm(l?)$ product\.php\?fclassname=$1&fb_babrand=$3&code=$6 [NC]
RewriteRule ^(power([^/]*))/([^/]+)/(.+)\.htm(l?)$ product\.php\?fclassname=$1&fb_babrand=$3&code=$4 [NC]
RewriteRule ^(pda([^/]*))/([^/]+)/(.+)\.htm(l?)$ product\.php\?fclassname=$1&fb_babrand=$3&code=$4 [NC]
RewriteRule ^(mobile([^/]*))/([^/]+)/(.+)\.htm(l?)$ product\.php\?fclassname=$1&fb_babrand=$3&code=$4 [NC]
RewriteRule ^(two-way([^/]*))/([^/]+)/(.+)\.htm(l?)$ product\.php\?fclassname=$1&fb_babrand=$3&code=$4 [NC]
RewriteRule ^(scanner([^/]*))/([^/]+)/(.+)\.htm(l?)$ product\.php\?fclassname=$1&fb_babrand=$3&code=$4 [NC]
RewriteRule ^(mp3([^/]*))/([^/]+)/(.+)\.htm(l?)$ product\.php\?fclassname=$1&fb_babrand=$3&code=$4 [NC]
]]>
9) NS (used only if no internal sub-request) 只用于不是内部子h
10Q?NC(no case) 不区分大写
11) QSA(query string append) q加h字符?br />
12) NE(no URI escaping of output) 不在输出转义Ҏ(gu)字符
例如QRewriteRule /foo/(.*) /bar?arg=P1\%3d$1 [R,NE] 能正确的将/foo/zoo转换?bar?arg=P1=zed
13) PT(pass through to next handler) 传递给下一个处?br />
例如Q?br />
RewriteRule ^/abc(.*) /def$1 [PT] # 会交给/def规则处理
Alias /def /ghi
14) S=num(skip next rule(s)) 跌num条规?br />
15) E=VAR:VAL(set environment variable) 讄环境变量
]]>
首先定(zhn)用的 Apache 版本Q及是否加蝲?mod_rewrite 模块?br />
Apache 1.x 的用戯?conf/httpd.conf 中是否存在如下两D代码:
LoadModule rewrite_module libexec/mod_rewrite.so
AddModule mod_rewrite.c
Apache 2.x 的用戯?conf/httpd.conf 中是否存在如下一D代码:
LoadModule rewrite_module modules/mod_rewrite.so
如果存在Q那么在配置文gQ通常是 conf/httpd.confQ中加入如下代码。此时请务必注意Q如果网?br />
使用通过虚拟L来定义,请务必加到虚拟主机配|,?<VirtualHost> 中去Q如果加在虚拟主机配|外
部将可能无法使用。改好后然后?Apache 重启?/p>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^(.*)/forum-([0-9]+)-([0-9]+)-([0-9]+).html[?]{0,1}(.*)$ $1/forumdisplay.php
?f=$2&st=$4&pp=$3&$5
RewriteRule ^(.*)/forum-([0-9]+)-([0-9]+).html[?]{0,1}(.*)$ $1/forumdisplay.php?f=$2&pp=$3&$4
RewriteRule ^(.*)/forum-([0-9]+)-(q?)-([0-9]+).html[?]{0,1}(.*)$ $1/forumdisplay.php
?f=$2&filter=quintessence&pp=$3&$4
RewriteRule ^(.*)/forum-([0-9]+)-(q?).html[?]{0,1}(.*)$ $1/forumdisplay.php
?f=$2&filter=quintessence&$4
RewriteRule ^(.*)/forum-([0-9]+).html[?]{0,1}(.*)$ $1/forumdisplay.php?f=$2&$3
RewriteRule ^(.*)/thread-([0-9]+)-([0-9]+).html[?]{0,1}(.*)$ $1/showthread.php?t=$2&pp=$3&$4
RewriteRule ^(.*)/thread-([0-9]+).html[?]{0,1}(.*)$ $1/showthread.php?t=$2&$3
RewriteRule ^(.*)/user-([0-9]+).html $1/profile.php?u=$2[L]
RewriteRule ^(.*)/archive/f-([0-9]+)-([0-9]+).html $1/index.php?f$2-$3.html[L]
RewriteRule ^(.*)/archive/t-([0-9]+)-([0-9]+).html $1/index.php?t$2-$3.html[L]
</IfModule>
如果没有安装 mod_rewriteQ?zhn)可以重新~译 ApacheQƈ在原?configure 的内容中加入
--enable-rewrite=sharedQ然后再?Apache 配置文g中加入上qC码即可?
Apache Web ServerQ虚拟主机用P
在开始以下设|之前,请首先咨询?zhn)的空间服务商Q空间是否支?Rewrite 以及是否支持对站?
目录?.htaccess 的文件解析,否则即便按照下面的方法设|好了,也无法用?
查论坛所在目录中是否存在 .htaccess 文gQ如果不存在Q请手工建立此文件。Win32 pȝ?
Q无法直接徏?.htaccess 文gQ?zhn)可以从其他系l中拯一份,或者在 力论坛技术支持栏?
中下载此文g。编辑ƈ修改 .htaccess 文gQ添加以下内?:
# ?RewriteEngine 模式打开
RewriteEngine On
# 修改以下语句中的 /molyx_board Z的论坛目录地址Q如果程序放在根目录中,请将
/molyx_board 修改?/
RewriteBase /molyx_board/
# Rewrite pȝ规则请勿修改
RewriteRule forum-([0-9]+)-([0-9]+)-([0-9]+).html forumdisplay.php?f=$1&st=$3&pp=$2&$4
RewriteRule forum-([0-9]+)-([0-9]+).html forumdisplay.php?f=$1&pp=$2&$3
RewriteRule forum-([0-9]+)-(q?)-([0-9]+).html forumdisplay.php?f=$1&filter=quintessence&pp=$3
RewriteRule forum-([0-9]+)-(q?).html forumdisplay.php?f=$1&filter=quintessence
RewriteRule forum-([0-9]+).html forumdisplay.php?f=$1
RewriteRule thread-([0-9]+)-([0-9]+).html showthread.php?t=$1&pp=$2&$3
RewriteRule thread-([0-9]+).html showthread.php?t=$1&$2
RewriteRule user-([0-9]+).html profile.php?u=$1
RewriteRule archive/f-([0-9]+)-([0-9]+).html archive/index.php?f$1-$2.html
RewriteRule archive/t-([0-9]+)-([0-9]+).html archive/index.php?t$1-$2.html
以上为开启URL静态化的整个说明?/pre>
本h是独立主机,按照上面做,一直没有成功。开启静态化后,提示
# ?RewriteEngine 模式打开
RewriteEngine On
# 修改以下语句中的 /molyx_board Z的论坛目录地址Q如果程序放在根目录中,请将
/molyx_board 修改?/
RewriteBase /molyx_board/
# Rewrite pȝ规则请勿修改
RewriteRule forum-([0-9]+)-([0-9]+)-([0-9]+).html forumdisplay.php?f=$1&st=$3&pp=$2&$4
RewriteRule forum-([0-9]+)-([0-9]+).html forumdisplay.php?f=$1&pp=$2&$3
RewriteRule forum-([0-9]+)-(q?)-([0-9]+).html forumdisplay.php?f=$1&filter=quintessence&pp=$3
RewriteRule forum-([0-9]+)-(q?).html forumdisplay.php?f=$1&filter=quintessence
RewriteRule forum-([0-9]+).html forumdisplay.php?f=$1
RewriteRule thread-([0-9]+)-([0-9]+).html showthread.php?t=$1&pp=$2&$3
RewriteRule thread-([0-9]+).html showthread.php?t=$1&$2
RewriteRule user-([0-9]+).html profile.php?u=$1
RewriteRule archive/f-([0-9]+)-([0-9]+).html archive/index.php?f$1-$2.html
RewriteRule archive/t-([0-9]+)-([0-9]+).html archive/index.php?t$1-$2.html
]]>
注:后来研究发现是resin提供的session id reuseҎ(gu),只是此文W一ơ发布时我还不知道有此特性,惭愧?br />
在servlet规范中,HttpServletSession的获取时通过调用request.getSession(boolean createnew)Ҏ(gu)来实玎ͼ其实现机制可以简单的理解? 存在一个大的hashMapl构Qkey是jsessionidQ而valule是HttpservletSession对象。request.getSession(boolean createnew)Ҏ(gu)通过jsessionid来获取对应的HttpservletSessionQ如果不存在q且参数createnew=trueQ则创徏一个新的HttpservletSession对象Qƈ讄jsessionid=session.getId() Q保存到hashMapl构中。以后再传递这个jsessionid. Q详l的q程比较复杂Q各家的实现也不相同,但大体的实现原理是如此。)
x以下几点Q?br />
一). 获取jsessionid
jsessionid的传递可以是以下途径
1. 攑֜cookie?br />
Cookie: JSESSIONID=abcrmF3Gx-5Z-hhkgHfzr
2. 以参数Ş式放在url
http://10.3.2.35:11280/wmail/welcome.action?jsessionid=abcQNqiT4C01rg-necLBr
3. 用form表单传递,通常是用隐藏?br />
<input type="hidden" name="jsessionid" value="abcQNqiT4C01rg-necLBr"/>
4. url重写
http://10.3.2.35:11280/jid=abcQNqiT4C01rg-necLBr/wmail/welcome.action
或?br />
http://10.3.2.35:11280/wmail/welcome.action;jsessionid=abcQNqiT4C01rg-necLBr
如果当前q没有jsessionid则当然就无法获取Q通常用户W一ơ访问或者登录前是q种情况.
可以通过request.getRequestedSessionId() Ҏ(gu)来获取本ơhttp h的jsessonid倹{?br />
二)获取到的HttpServletSession对象
如果HttpServletSession对象是已l存在的Q则
1. session.isNew()=false
2. request.getRequestedSessionId() == jsessionid == session.getId()
如果HttpServletSession对象是调用request.getSession(true) (写的request.getSession()Ҏ(gu){同于request.getSession(true) )时新创徏的,则有以下特征Q?br />
1. session.isNew()=true
2. 以后传递的jsessionid=session.getId()
注意q里Q如果request.getRequestedSessionId() 是空|情况比较单,以后传递jsessionid=session.getId()是了?br />
但是如果request.getRequestedSessionId() 不是I|通过q个值没有获取到已经存在的session对象Q而是q回了一个新的session对象Q这个时候新的session.getId()和原有的request.getRequestedSessionId() 关系如何呢?下面详细阐述q种情况?br />
? request.getRequestedSessionId() 不是I值时Q新的session.getId() = ?
1). 试代码如下:
HttpServletRequest request = ServletActionContext.getRequest();
String jid1 = request.getRequestedSessionId();
HttpSession session = request.getSession(true);
String jid2 = request.getRequestedSessionId();
logger.info("get HttpSession , isNew()=" + session.isNew()
+ " getId()=" + session.getId()
+ " and jid1=" + jid1
+ " and jid2=" + jid2);
其中jid1和jid2分别是调用request.getSession(true)Ҏ(gu)前后的request.getRequestedSessionId()倹{?br />
在resin中运行以上代码,试request.getRequestedSessionId() 不是ID对应jsessionid的session不存在的情况?br />
2). 通过cookie来传递jsessionid的情况,试l果如下Q?br />
get HttpSession, isNew()=true getId()=abcqIgQroQ2Ov9lGYcYAr and jid1=abcqIgQroQ2Ov9lGYcYAr and jid2=abcqIgQroQ2Ov9lGYcYAr
get HttpSession, isNew()=true getId()=abcPQ3mpxKz8H-4UMdYAr and jid1=abcPQ3mpxKz8H-4UMdYAr and jid2=abcPQ3mpxKz8H-4UMdYAr
get HttpSession, isNew()=true getId()=abcdeE3iDy_bI536tLYAr and jid1=abcdeE3iDy_bI536tLYAr and jid2=abcdeE3iDy_bI536tLYAr
可以发现以下规律Q?br />
1. isNew()=true
2. session.getId() == jid1 == jid2
x创徏的session会用传递过来的jsessionid|即ɘq个jsessionid值根本没有对应的session存在
3) 通过url重写Q将jsessionid放url中传? 试l果如下Q?br />
get HttpSession, isNew()=true getId()=abccw1zEC_RcN43qHMYAr and jid1=abcdUdTfKuLbge8h_LYAr and jid2=abcdUdTfKuLbge8h_LYAr
http://10.3.2.35:11280/jid=abccw1zEC_RcN43qHMYAr/uab/contactList.action
get HttpSession, isNew()=true getId()=abcFK7yOB1irgaYqgNYAr and jid1=abci-HpMPJU3egCB7MYAr and jid2=abci-HpMPJU3egCB7MYAr
http://10.3.2.35:11280/jid=abcFK7yOB1irgaYqgNYAr/uab/contactList.action
(后面的http地址为页面蟩转完成后昄在浏览器地址框中的页面url)
可以发现以下规律Q?br />
1. isNew()=true
2. jid1 == jid2
request.getRequestedSessionId()值在request.getSession(true)Ҏ(gu)调用前后无变?br />
3. session.getId() != jid1
x创徏的session不用传递过来的jsessionid?而是采用新?br />
4. 跌{完成后的http地址?使用的是session.getId(), 而不是原来通过url重写传递过来的jsessionid
此时新的jsessionid覆盖了旧有的jsessionid.
4) ȝ
在resin的实C, 通过cookie来传递jsessionid的情况和通过url重写jsessionid放url中传? 会有l微的差?
以上试的resin版本?.0.26, E后有时间考虑试其他版本和tomcat.
q个差异直接影响到跨webapp的多个webapp直接怺传递jsessionid的方? 通过cookie传递jsessionid可以做到多个webapp之间在页面蟩转时始终是一个相同的jsessionid,q种各个应用都可以方便的获取到自qHttpServletSession对象. 但是如果是通过url重写,则破坏了jsessonid的一致? D各个webapp之间跌{时必ȝ其他额外的方法来保证传递给Ҏ(gu)的jsessionid的准?因ؓ此时每个webapp的jsessionid都不一样了,必须C其他每个webapp的jsessionidQ造成跨webapp的页面蟩转极其复杂,难于接受.
]]>
<filter-mapping>
<filter-name>Struts2</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<filter>
<filter-name>struts-cleanup</filter-name>
<filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>
</filter>
<filter-mapping>
<filter-name>struts-cleanup</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
按照Struts2的APIQfilter的顺序是
struts-cleanup filter
SiteMesh filter
FilterDispatcher
<web-app xmlns="http://caucho.com/ns/resin">
<servlet-mapping url-pattern='*.bbscs' servlet-name='plugin_match'/>
</web-app>
struts.url.includeParams=none
或是?lt;s:url/>标记中将includeParams属性设为none
另外q有两个?
all,是把get和post中的参数加入到url参数?
get,是只把get中的参数加入到url参数?
]]>
Java代码
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>MySqlDS</jndi-name> //jndi名字
<use-java-context>false</use-java-context>
<connection-url>jdbc:mysql://10.16.175.137:3306/test</connection-url> //URL地址
<driver-class>com.mysql.jdbc.Driver</driver-class> //驱动
<user-name>root</user-name> //用户?nbsp;
<password>123456</password> //密码
<exception-sorter-class-name>
org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
</exception-sorter-class-name>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>MySqlDS</jndi-name> //jndi名字
<use-java-context>false</use-java-context>
<connection-url>jdbc:mysql://10.16.175.137:3306/test</connection-url> //URL地址
<driver-class>com.mysql.jdbc.Driver</driver-class> //驱动
<user-name>root</user-name> //用户?nbsp;
<password>123456</password> //密码
<exception-sorter-class-name>
org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
</exception-sorter-class-name>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>
看一下这个文?里面用户名与密码都是以明文方式存储的,q样子对pȝ的安全而言带来了极大的威协。所以我们要为我们这个明文的密码加一下密,q就是本文的目的.
2.说到密码加密Q这里我们用CJBoss下的一个类org.jboss.resource.security.SedureIdentityLoginModule,看看我们该如何用它来帮我们的密码加密?
先看个配|数据源的例?mysql-ds.xml)Q?
Java代码
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>MySqlDS</jndi-name>
<use-java-context>false</use-java-context>
<connection-url>jdbc:mysql://192.168.1.91:3306/atteam</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<security-domain>EncryptDBPassword</security-domain>//q里不用写上你的用户名与密码了,我们可以在login-config.xml里做Ҏ(gu)脚,O(jin)K?nbsp;
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>MySqlDS</jndi-name>
<use-java-context>false</use-java-context>
<connection-url>jdbc:mysql://192.168.1.91:3306/atteam</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<security-domain>EncryptDBPassword</security-domain>//q里不用写上你的用户名与密码了,我们可以在login-config.xml里做Ҏ(gu)脚,O(jin)K?br />
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>
接着我们修改server\default\conf\login-config.xml文g,加上下面q一D配|文?
Java代码
<application-policy name="EncryptDBPassword"> //q里的name应该是你在配|数据源时写的security-domain里的字符?nbsp;
<authentication>
<login-module code="org.jboss.resource.security.SecureIdentityLoginModule"
flag="required">
<module-option name="username">test</module-option> //数据库的用户?nbsp;
<module-option name="password">64c5fd2979a86168</module-option> //数据库的密码Q不q是加密q的?nbsp;
<module-option name="managedConnectionFactoryName">jboss.jca:service=LocalTxCM,name=MySqlDS</module-option>
//注意name{于你的数据源的jndi-name,q里是MySqlDS
</login-module>
</authentication>
</application-policy>
<application-policy name="EncryptDBPassword"> //q里的name应该是你在配|数据源时写的security-domain里的字符?br />
<authentication>
<login-module code="org.jboss.resource.security.SecureIdentityLoginModule"
flag="required">
<module-option name="username">test</module-option> //数据库的用户?br />
<module-option name="password">64c5fd2979a86168</module-option> //数据库的密码Q不q是加密q的?br />
<module-option name="managedConnectionFactoryName">jboss.jca:service=LocalTxCM,name=MySqlDS</module-option>
//注意name{于你的数据源的jndi-name,q里是MySqlDS
</login-module>
</authentication>
</application-policy>
3.补充一下,q个加密的密码是哪来的(呵呵Q忘了说了)
java -cp "D:\TDdownload\jboss-4.2.0.CR1\jboss-4.2.0.CR1\lib\jboss-jmx.jar;D:\TDdownload\jboss-4.2.0.CR1\jboss-4.2.0.CR1\lib\jboss-common.jar;D:\TDdownload\jboss-4.2.0.CR1\jboss-4.2.0.CR1\server\default\lib\jboss-jca.jar;D:\TDdownload\jboss-4.2.0.CR1\jboss-4.2.0.CR1\server\default\lib\jbosssx.jar" org.jboss.resource.security.SecureIdentityLoginModule 123456
Encoded password: 64c5fd2979a86168
写上你自q路径和你要加密的密码p?我这里要加密的密码是123456,加密q之后就?4c5fd2979a86168